views:

52

answers:

2

Edit

I've added the following code, however I get an error @ SendInput:

File I/O of a structure with field 'dwExtraInfo' of type 'IntPtr' is not valid

Public Sub DoDoubleClick(ByVal wait As Integer, ByVal x As Integer, ByVal y As Integer)
    Dim inputEvents(0) As Input
    Dim p As MOUSEKEYBDHARDWAREINPUT

    p.mi.dx = x
    p.mi.dy = y
    p.mi.mouseData = 0
    p.mi.dwFlags = MOUSEEVENTF_MOVE + MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP

    inputEvents(0).dwType = 0
    inputEvents(0).mkhi = p

    SendInput(1, inputEvents(0), Len(inputEvents(0)))

    System.Threading.Thread.Sleep(wait)

    'SendInput(1, inputEvents(0), Len(inputEvents(0)))
End Sub

Original question:

I'm trying to programmatically invoke an onclick event however the click is not received/handled. Am I missing something, or is security preventing the click to be executed?

I have a forms application which is invisible. Basically I would like to say:

DoDoubleClick(wait, x, y)

This should raise two click (mousedown+mouseup) events on screen with the specified wait interval. However the click isn't received in a Flash application in Firefox (which is running at that moment).

Here's my code:

Form:

Public Class Form1
    Private WithEvents gmh As GlobalMouseHook

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        gmh = New GlobalMouseHook()
        Me.Visible = false
        gmh.DoDoubleClick(50, 800, 600)
    End Sub

    Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        gmh.Dispose()
    End Sub

    Private Sub gmh_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles gmh.MouseDown

    End Sub

    Private Sub gmh_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles gmh.MouseMove

    End Sub

    Private Sub gmh_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles gmh.MouseUp

    End Sub

End Class

GlobalMouseHook class:

Friend Class GlobalMouseHook
    Implements IDisposable

    Private hhk As IntPtr = IntPtr.Zero
    Private disposedValue As Boolean = False 

    Public Event MouseDown As MouseEventHandler
    Public Event MouseUp As MouseEventHandler
    Public Event MouseMove As MouseEventHandler

    Public Sub New()
        Hook()
    End Sub

    Private Sub Hook()
        Dim hInstance As IntPtr = LoadLibrary("User32")
        hhk = SetWindowsHookEx(WH_MOUSE_LL, AddressOf Me.HookProc, hInstance, 0)
    End Sub

    Private Sub Unhook()
        UnhookWindowsHookEx(hhk)
    End Sub

    Public Sub DoDoubleClick(ByVal wait As Integer, ByVal x As Integer, ByVal y As Integer)
        RaiseEvent MouseDown(Me, New MouseEventArgs(MouseButtons.Left, 1, x, y, 0))
        RaiseEvent MouseUp(Me, Nothing)

        System.Threading.Thread.Sleep(wait)

        RaiseEvent MouseDown(Me, New MouseEventArgs(MouseButtons.Left, 1, x, y, 0))
        RaiseEvent MouseUp(Me, Nothing)
    End Sub

    Private Function HookProc(ByVal nCode As Integer, ByVal wParam As UInteger, ByRef lParam As MSLLHOOKSTRUCT) As Integer
        If nCode >= 0 Then
            Select Case wParam
                Case WM_LBUTTONDOWN
                    RaiseEvent MouseDown(Me, New MouseEventArgs(MouseButtons.Left, 0, lParam.pt.x, lParam.pt.y, 0))
                Case WM_RBUTTONDOWN
                    RaiseEvent MouseDown(Me, New MouseEventArgs(MouseButtons.Right, 0, lParam.pt.x, lParam.pt.y, 0))
                Case WM_MBUTTONDOWN
                    RaiseEvent MouseDown(Me, New MouseEventArgs(MouseButtons.Middle, 0, lParam.pt.x, lParam.pt.y, 0))
                Case WM_LBUTTONUP, WM_RBUTTONUP, WM_MBUTTONUP
                    RaiseEvent MouseUp(Nothing, Nothing)
                Case WM_MOUSEMOVE
                    RaiseEvent MouseMove(Nothing, Nothing)
                Case WM_MOUSEWHEEL, WM_MOUSEHWHEEL
                Case Else
                    Console.WriteLine(wParam)
            End Select
        End If
        Return CallNextHookEx(hhk, nCode, wParam, lParam)
    End Function

    Private Structure API_POINT
        Public x As Integer
        Public y As Integer
    End Structure

    Private Structure MSLLHOOKSTRUCT
        Public pt As API_POINT
        Public mouseData As UInteger
        Public flags As UInteger
        Public time As UInteger
        Public dwExtraInfo As IntPtr
    End Structure

    Private Const WM_MOUSEWHEEL As UInteger = &H20A
    Private Const WM_MOUSEHWHEEL As UInteger = &H20E
    Private Const WM_MOUSEMOVE As UInteger = &H200
    Private Const WM_LBUTTONDOWN As UInteger = &H201
    Private Const WM_LBUTTONUP As UInteger = &H202
    Private Const WM_MBUTTONDOWN As UInteger = &H207
    Private Const WM_MBUTTONUP As UInteger = &H208
    Private Const WM_RBUTTONDOWN As UInteger = &H204
    Private Const WM_RBUTTONUP As UInteger = &H205
    Private Const WH_MOUSE_LL As Integer = 14

    Private Delegate Function LowLevelMouseHookProc(ByVal nCode As Integer, ByVal wParam As UInteger, ByRef lParam As MSLLHOOKSTRUCT) As Integer

    Private Declare Auto Function LoadLibrary Lib "kernel32" (ByVal lpFileName As String) As IntPtr
    Private Declare Auto Function SetWindowsHookEx Lib "user32.dll" (ByVal idHook As Integer, ByVal lpfn As LowLevelMouseHookProc, ByVal hInstance As IntPtr, ByVal dwThreadId As UInteger) As IntPtr
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As UInteger, ByRef lParam As MSLLHOOKSTRUCT) As Integer
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hhk As IntPtr) As Boolean



    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: free other state (managed objects).
            End If

            Unhook()
        End If
        Me.disposedValue = True
    End Sub

    ' This code added by Visual Basic to correctly implement the disposablepattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByValdisposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

End Class
+1  A: 

Just call SendInput twice with a short delay between. Here's a codeproject article that seems to be doing something similar to what you want.

ho1
I really have NO idea what's going on there. I have no knowledge at all using marshal or interop services.... I'm unable to just copy-paste and translate to VB. Lots of compile errors... Is it possible to call `SendInput` somewhere in my code?
Ropstah
Please check my updated question...
Ropstah
@ropstah: Sorry, I don't have time to look in details now, but if it's just a matter problem converting the codeproject article, have you tried using one of the converters? Like http://www.developerfusion.com/tools/convert/csharp-to-vb/ . Otherwise, try looking at http://www.pinvoke.net/default.aspx/user32.sendinput, they've got a VB.Net sample (start with copying the `DoMouse` method and then copy the other code as needed to make it compile).
ho1
A: 

Try this library, it is fairly straightforward and seems to work well.

Chris Dunaway