As Tesla... suggests indirectly, there are limited ways to simulate
mouse events in Windows. We have both mouse_events (deprecated) and
SendInput -- neither of which are managed code.
I have searched the net at length and attacked this "simple" problem
for many hours so I'm hoping my efforts will pay off for you.
This is a VB.NET 2005 test bed solution that allows you to play with
mouse_event, SendInput, and OnMouse... techniques. The OnMouse...
approach has yet to yield fruits. Either other approach (comment out
the other 2; uncomment the METHOD desired) work quite well.
This example expects a form called frmMain, a picture box called
picClick, three buttons: (btnClickStart, btnClick, btnScreen), and a
multi-line text box called txtResults.
This is an amalgam primarily based on
http://vb-helper.com/howto_move_click_mouse.html and
http://www.vbforums.com/showthread.php?t=398899 -- I'm trying to update
http://www.pinvoke.net/ to share this information.
Also, this code shows how to simulate a "union struct" in VB.NET -- I
was pleased to figure this out.
Rick Valstar
Star Consulting
r + last name + at + gmail + dot + com
Here's the code:
Option Explicit On
Imports System.Runtime.InteropServices
Public Class frmMain
'Const METHOD As String = "mouse_event"
'Const METHOD As String = "OnMouse"
Const METHOD As String = "SendInput"
Const INPUT_MOUSE As Int32 = 0
Const INPUT_KEYBOARD As Int32 = 1
Const INPUT_HARDWARE As Int32 = 2
Const MOUSEEVENTF_MOVE As Int32 = &H1 ' mouse move
Const MOUSEEVENTF_LEFTDOWN As Int32 = &H2 ' left button down
Const MOUSEEVENTF_LEFTUP As Int32 = &H4 ' left button up
Const MOUSEEVENTF_RIGHTDOWN As Int32 = &H8 ' right button down
Const MOUSEEVENTF_RIGHTUP As Int32 = &H10 ' right button up
Const MOUSEEVENTF_MIDDLEDOWN As Int32 = &H20 ' middle button down
Const MOUSEEVENTF_MIDDLEUP As Int32 = &H40 ' middle button up
Const MOUSEEVENTF_ABSOLUTE As Int32 = &H8000 ' absolute move
Const MOUSEEVENTF_WHEEL As Int32 = &H800 ' wheel button rolled
Private Structure MOUSEINPUT
Dim dx As Int32
Dim dy As Int32
Dim mouseData As Int32
Dim dwFlags As Int32
Dim time As Int32
Dim dwExtraInfo As IntPtr
End Structure
Private Structure KEYBDINPUT
Dim wVk As Int16
Dim wScan As Int16
Dim dwFlags As Int32
Dim time As Int32
Dim dwExtraInfo As IntPtr
End Structure
Private Structure HARDWAREINPUT
Dim uMsg As Int32
Dim wParamL As Int16
Dim wParamH As Int16
End Structure
<StructLayout(LayoutKind.Explicit)> _
Private Structure INPUT
<FieldOffset(0)> Dim dwType As Int32
' simulate a union struct (C) or a variant record (Pascal)
<FieldOffset(4)> Dim mi As MOUSEINPUT
<FieldOffset(4)> Dim ki As KEYBDINPUT
<FieldOffset(4)> Dim hi As HARDWAREINPUT
End Structure
Private Declare Auto Sub mouse_event Lib "user32.dll" (ByVal
dwFlags As Int32, ByVal dx As Int32, ByVal dy As Int32, ByVal cButtons
As Int32, ByVal dwExtraInfo As IntPtr)
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function SendInput(ByVal nInputs As Int32, ByRef
pInputs As INPUT, ByVal cbSize As Int32) As Int32
End Function
Private Declare Auto Sub SetLastError Lib "kernel32.dll" (ByVal
dwErrCode As Int32)
Sub ClickMouse(ByVal MouseButton As Integer)
Dim inputevents As New INPUT
inputevents.mi.dx = 0
inputevents.mi.dy = 0
inputevents.mi.mouseData = 0
inputevents.mi.dwFlags = MouseButton
inputevents.mi.time = 0
inputevents.dwType = INPUT_MOUSE
SetLastError(0)
Dim result As Integer = SendInput(1, inputevents,
Marshal.SizeOf(GetType(INPUT)))
Dim lasterror As Integer = Marshal.GetLastWin32Error
Debug.WriteLine("Result: " & result)
Debug.WriteLine("LastError: " & lasterror & " " & New
System.ComponentModel.Win32Exception(lasterror).Message)
End Sub
Sub btnClickStart_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnClickStart.Click
txtResults.AppendText("***** btnClickStart *****" & vbCrLf)
'move mouse to the start button
Dim pt As New System.Drawing.Point(20,
Screen.PrimaryScreen.Bounds.Height - 20)
'Dim pt As Point = picClicker.PointToScreen(New
Point(picClicker.ClientRectangle.Width / 2,
picClicker.ClientRectangle.Height / 2))
Debug.WriteLine("pt " & pt.X & " " & pt.Y)
System.Windows.Forms.Cursor.Position = pt
Windows.Forms.Application.DoEvents()
ClickMouse(MOUSEEVENTF_LEFTDOWN) 'press left button
ClickMouse(MOUSEEVENTF_LEFTUP) 'release left button
End Sub
Private Sub btnClick_Click(ByVal eventSender As System.Object,
ByVal eventArgs As System.EventArgs) Handles btnClick.Click
Dim cur_x As Single
Dim cur_y As Single
Dim dest_x As Single
Dim dest_y As Single
txtResults.AppendText("***** btnClick *****" & vbCrLf)
' mouse_event moves in a coordinate system where (0, 0) is in
the upper left corner and (65535,65535) is in the lower right corner.
' Get the current mouse coordinates and convert them into this
new system.
cur_x = System.Windows.Forms.Cursor.Position.X * 65535 /
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width
cur_y = System.Windows.Forms.Cursor.Position.Y * 65535 /
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
' Convert the coordinates of the center of the picClicker
PictureBox into this new system.
Dim pt As Point = picClicker.PointToScreen(New
Point(picClicker.ClientRectangle.Width / 2,
picClicker.ClientRectangle.Height / 2))
'Dim pt As New System.Drawing.Point(20,
Screen.PrimaryScreen.Bounds.Height - 20)
dest_x = pt.X * 65535 /
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width
dest_y = pt.Y * 65535 /
System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
txtResults.AppendText("From " &
System.Windows.Forms.Cursor.Position.X & " " &
System.Windows.Forms.Cursor.Position.Y & " to " & pt.X & " " & pt.Y &
vbCrLf)
txtResults.AppendText("From " & cur_x & " " & cur_y & " to " &
dest_x & " " & dest_y & vbCrLf)
' Move the mouse to its final destination and click it.
Select Case METHOD
Case "OnMouse"
System.Windows.Forms.Cursor.Position = pt
Windows.Forms.Application.DoEvents()
'Dim eMouseMove As New
System.Windows.Forms.MouseEventArgs(Windows.Forms.MouseButtons.None, 0,
pt.X, pt.Y, 0)
'Me.OnMouseMove(eMouseMove)
Dim eMouseButton As New
System.Windows.Forms.MouseEventArgs(Windows.Forms.MouseButtons.Left, 1,
0, 0, 0)
Me.OnMouseDown(eMouseButton)
Me.OnMouseUp(eMouseButton)
Case "mouse_event"
mouse_event(MOUSEEVENTF_ABSOLUTE + MOUSEEVENTF_MOVE +
MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP, dest_x, dest_y, 0, 0)
Case "SendInput"
Dim pInputs(0 To 2) As INPUT
With pInputs(0)
.dwType = INPUT_MOUSE
.mi.dx = dest_x
.mi.dy = dest_y
.mi.mouseData = 0
.mi.dwFlags = MOUSEEVENTF_ABSOLUTE +
MOUSEEVENTF_MOVE
.mi.time = 0
.mi.dwExtraInfo = IntPtr.Zero
End With
With pInputs(1)
.dwType = INPUT_MOUSE
.mi.dx = 0
.mi.dy = 0
.mi.mouseData = 0
.mi.dwFlags = MOUSEEVENTF_LEFTDOWN
.mi.time = 0
.mi.dwExtraInfo = IntPtr.Zero
End With
With pInputs(2)
.dwType = INPUT_MOUSE
.mi.dx = 0
.mi.dy = 0
.mi.mouseData = 0
.mi.dwFlags = MOUSEEVENTF_LEFTUP
.mi.time = 0
.mi.dwExtraInfo = IntPtr.Zero
End With
'System.Windows.Forms.Cursor.Position = pt
'Windows.Forms.Application.DoEvents()
'Debug.WriteLine("Size: " & Marshal.SizeOf(pInputs(0))
& " " & Marshal.SizeOf(GetType(INPUT)))
SetLastError(0)
Debug.WriteLine("Result: " & SendInput(3, pInputs(0),
Marshal.SizeOf(GetType(INPUT))))
Debug.WriteLine("LastError: " &
Marshal.GetLastWin32Error & " " & New
System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error).Message)
'SetLastError(0)
'Debug.WriteLine("Result: " & SendInput(1, pInputs(1),
Marshal.SizeOf(GetType(INPUT))))
'Debug.WriteLine("LastError: " &
Marshal.GetLastWin32Error & " " & New
System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error).Message)
'SetLastError(0)
'Debug.WriteLine("Result: " & SendInput(1, pInputs(2),
Marshal.SizeOf(GetType(INPUT))))
'Debug.WriteLine("LastError: " &
Marshal.GetLastWin32Error & " " & New
System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error).Message)
Case Else
Beep()
End Select
'Windows.Forms.Application.DoEvents()
'My.Application.DoEvents()
End Sub
Private Sub btnScreen_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnScreen.Click
Dim I As Integer
Dim Screens() As System.Windows.Forms.Screen =
System.Windows.Forms.Screen.AllScreens
txtResults.AppendText("***** btnScreen *****" & vbCrLf)
For I = 0 To Screens.GetUpperBound(0)
txtResults.AppendText("Device Name: " +
Screens(I).DeviceName & vbCrLf)
txtResults.AppendText("Bounds: " +
Screens(I).Bounds.ToString() & vbCrLf)
txtResults.AppendText("Type: " +
Screens(I).GetType().ToString() & vbCrLf)
txtResults.AppendText("Working Area: " +
Screens(I).WorkingArea.ToString() & vbCrLf)
txtResults.AppendText("Primary Screen: " +
Screens(I).Primary.ToString() & vbCrLf)
Next I
End Sub
Private Sub picClicker_Click(ByVal eventSender As System.Object,
ByVal eventArgs As System.EventArgs) Handles picClicker.Click
txtResults.AppendText("picClicker_Click" & vbCrLf)
End Sub
Private Sub picClicker_MouseDown(ByVal sender As System.Object,
ByVal e As System.Windows.Forms.MouseEventArgs) Handles
picClicker.MouseDown
txtResults.AppendText("picClicker_MouseDown (" & e.X & ", " &
e.Y & ")" & vbCrLf)
End Sub
Private Sub picClicker_MouseUp(ByVal sender As System.Object, ByVal
e As System.Windows.Forms.MouseEventArgs) Handles picClicker.MouseUp
txtResults.AppendText("picClicker_MouseUp (" & e.X & ", " & e.Y
& ")" & vbCrLf)
End Sub
Private Sub frmMain_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Click
txtResults.AppendText("frmMain_Click" & vbCrLf)
End Sub
Private Sub frmMain_MouseDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
txtResults.AppendText("frmMain_MouseDown (" & e.X & ", " & e.Y
& ")" & vbCrLf)
End Sub
Private Sub frmMain_MouseUp(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
txtResults.AppendText("frmMain_MouseUp (" & e.X & ", " & e.Y &
")" & vbCrLf)
End Sub
End Class