使用64位系统的SendKey键盘鼠标模拟

时间:2013-02-14 11:36:48

标签: .net vb.net

我刚才写了一组发送键功能。它在32位系统中工作。现在我再次测试它并意识到它不再适用于我的新win7 64位系统。 我在网上找到了一些文章,然后按their way来创建Input32 / 64函数。但它似乎不起作用。

Dim result As Integer = SendInput(1, input, cbSize)

始终返回0并且没有模拟击键。你能看一下吗?

(注意:我只做了KEYBOARDINPUT64结构,它不起作用,所以我没有制作MOUSEINPUT64或HARDWAREINPUT64结构......)

''mouse functions

Private Shared Sub SendMouseInput(ByVal flags As MOUSEEVENTF, ByVal point As System.Drawing.Point)
    If Marshal.SizeOf(New IntPtr()) = 8 Then
        SendMouseInput64(flags, point)
    Else
        SendMouseInput32(flags, point)
    End If
End Sub
Private Shared Sub SendMouseInput64(ByVal flags As MOUSEEVENTF, ByVal point As System.Drawing.Point)
    Dim screen As Rectangle = My.Computer.Screen.Bounds
    Dim globalx As Integer = CInt((65535 * point.X) / screen.Width) ' x scale from 0 to 65535
    Dim globaly As Integer = CInt((65535 * point.Y) / screen.Height) ' y scale from 0 to 65535
    Dim input As New INPUT64
    input.dwType = InputType.Mouse
    input.mi.dx = globalx
    input.mi.dy = globaly
    input.mi.dwFlags = MOUSEEVENTF.ABSOLUTE Or flags
    input.mi.dwExtraInfo = IntPtr.Zero
    input.mi.mouseData = 0
    input.mi.time = 0
    SendInput(1, input, Marshal.SizeOf(input))
End Sub
Private Shared Sub SendMouseInput32(ByVal flags As MOUSEEVENTF, ByVal point As System.Drawing.Point)
    Dim screen As Rectangle = My.Computer.Screen.Bounds
    Dim globalx As Integer = CInt((65535 * point.X) / screen.Width) ' x scale from 0 to 65535
    Dim globaly As Integer = CInt((65535 * point.Y) / screen.Height) ' y scale from 0 to 65535
    Dim input As New INPUT32
    input.dwType = InputType.Mouse
    input.mi.dx = globalx
    input.mi.dy = globaly
    input.mi.dwFlags = MOUSEEVENTF.ABSOLUTE Or flags
    input.mi.dwExtraInfo = IntPtr.Zero
    input.mi.mouseData = 0
    input.mi.time = 0
    SendInput(1, input, Marshal.SizeOf(input))
End Sub

''keyboard functions
Private Shared Sub SendKeyInput(ByVal flags As KEYEVENTF, ByVal key As Int16)
    If Marshal.SizeOf(New IntPtr()) = 8 Then
        SendKeyInput64(flags, key)
    Else
        SendKeyInput32(flags, key)
    End If
End Sub
Private Shared Sub SendKeyInput64(ByVal flags As KEYEVENTF, ByVal key As Int16)
    Dim input As New INPUT64
    Dim ki As New KEYBDINPUT64
    input.dwType = InputType.Keyboard
    input.ki = ki
    input.ki.wVk = key
    input.ki.wScan = 0
    input.ki.time = 0
    input.ki.dwFlags = flags
    input.ki.dwExtraInfo = IntPtr.Zero
    Dim cbSize As Integer = Marshal.SizeOf(GetType(INPUT64))
    Dim result As Integer = SendInput(1, input, cbSize)
    If result = 0 Then Console.WriteLine("SendKeyInput:" & Marshal.GetLastWin32Error)
End Sub
Private Shared Sub SendKeyInput32(ByVal flags As KEYEVENTF, ByVal key As Int16)
    Dim input As New INPUT32
    Dim ki As New KEYBDINPUT32
    input.dwType = InputType.Keyboard
    input.ki = ki
    input.ki.wVk = key
    input.ki.wScan = 0
    input.ki.time = 0
    input.ki.dwFlags = flags
    input.ki.dwExtraInfo = IntPtr.Zero
    Dim cbSize As Integer = Marshal.SizeOf(GetType(INPUT32))
    Dim result As Integer = SendInput(1, input, cbSize)
    If result = 0 Then Messaging.Instance.ReportError("MouseKeyboard::SendKeyInput:" & Marshal.GetLastWin32Error)
End Sub

''lower level input functions
<DllImport("User32.dll", SetLastError:=True)> _
Private Shared Function SendInput(ByVal nInputs As Integer, ByRef pInputs As INPUT64, ByVal cbSize As Integer) As Integer
End Function

<DllImport("User32.dll", SetLastError:=True)> _
Private Shared Function SendInput(ByVal nInputs As Integer, ByRef pInputs As INPUT32, ByVal cbSize As Integer) As Integer
End Function

<DllImport("User32.dll")> _
Private Shared Function BlockInput(ByVal fBlockIt As Boolean) As Boolean
End Function

<StructLayout(LayoutKind.Explicit, pack:=1)> _
Private Structure INPUT64
    <FieldOffset(0)> Public dwType As InputType
    <FieldOffset(8)> Public mi As MOUSEINPUT
    <FieldOffset(8)> Public ki As KEYBDINPUT64
    <FieldOffset(8)> Public hi As HARDWAREINPUT
End Structure

<StructLayout(LayoutKind.Explicit, pack:=1)> _
Private Structure INPUT32
    <FieldOffset(0)> Public dwType As InputType
    <FieldOffset(4)> Public mi As MOUSEINPUT
    <FieldOffset(4)> Public ki As KEYBDINPUT32
    <FieldOffset(4)> Public hi As HARDWAREINPUT
End Structure

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Private Structure MOUSEINPUT
    Public dx As Int32
    Public dy As Int32
    Public mouseData As Int32
    Public dwFlags As MOUSEEVENTF
    Public time As Int32
    Public dwExtraInfo As IntPtr
End Structure

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Private Structure KEYBDINPUT64
    <FieldOffset(0)> Public wVk As Int16
    <FieldOffset(2)> Public wScan As Int16
    <FieldOffset(4)> Public dwFlags As KEYEVENTF
    <FieldOffset(12)> Public time As Int32
    <FieldOffset(16)> Public dwExtraInfo As IntPtr
End Structure

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Private Structure KEYBDINPUT32
    Public wVk As Int16
    Public wScan As Int16
    Public dwFlags As KEYEVENTF
    Public time As Int32
    Public dwExtraInfo As IntPtr
End Structure

<StructLayout(LayoutKind.Sequential, pack:=1)> _
Private Structure HARDWAREINPUT
    Public uMsg As Int32
    Public wParamL As Int16
    Public wParamH As Int16
End Structure
Private Enum InputType As Integer
    Mouse = 0
    Keyboard = 1
    Hardware = 2
End Enum
<Flags()> _
Private Enum MOUSEEVENTF As Integer
    MOVE = &H1
    LEFTDOWN = &H2
    LEFTUP = &H4
    RIGHTDOWN = &H8
    RIGHTUP = &H10
    MIDDLEDOWN = &H20
    MIDDLEUP = &H40
    XDOWN = &H80
    XUP = &H100
    VIRTUALDESK = &H400
    WHEEL = &H800
    ABSOLUTE = &H8000
End Enum
<Flags()> _
Private Enum KEYEVENTF As Integer
    KEYDOWN = 0
    EXTENDEDKEY = 1
    KEYUP = 2
    [UNICODE] = 4
    SCANCODE = 8
End Enum

2 个答案:

答案 0 :(得分:2)

与此问题的解决方案不同,但您是否尝试过InputSimulator库:https://inputsimulator.codeplex.com/

我已经在32/64位版本的Windows上使用它而没有任何障碍。

答案 1 :(得分:1)

请看看这个。 C# PInvoking user32.dll on a 64 bit system

我想这也适用于其他user32.dll调用...

  1. 使用IntPtr而不是UIntrPtr:UIntPtr类型不符合CLS
  2. 永远不要使用“int”或“integer”作为lParam。您的代码将在64位窗口上崩溃。只使用IntPtr,“ref”结构或“out”结构。
  3. 永远不要使用“bool”,“int”或“integer”作为返回值。您的核心将在64位窗口上崩溃。只使用IntPtr。使用bool是不安全的 - pInvoke不能将IntPtr编组为布尔值。
  4. 使用“IntPtr”作为返回值,即使消息显示它没有返回任何有用的信息。
  5. Microsoft将System.Windows.Forms.Message结构的Msg成员定义为System.Int32 [1]。同时,SendMessage本机API将消息定义为类型UINT [2],这是一个32位无符号值。[3] 可在此处找到常见消息代码列表:http://www.vbcode.com/Asp/showsn.asp?theID=11797
  6. 您可以安全地输入“hWnd”作为“IntPtr”而不是“HandleRef”,但请确保您了解自己在做什么。如果您正在操作非托管组件或外部应用程序提供的窗口句柄,那么事情就会起作用(当其他应用程序可以自由操作窗口时,也可以保证)。但是,将IntPtr与托管表单和控件一起使用可能会导致代码在竞争条件下崩溃,因为.NET可以并且将在调用期间处理窗口句柄。如果使用得当,GC.KeepAlive()可以帮助解决这个问题。这些都与钉扎无关,这在这里无济于事。固定是为了防止数据移动;使用HandleRef或GC.KeepAlive是为了防止运行时破坏你的句柄。
  7. 将整数值传递给lParam和wParam时,默认情况下使用IntPtr获取属性。您应该避免将IntPtr和Integer混合为参数类型。使用IntPtr。
  8. wParam和lParam参数分别定义为WPARAM和LPARAM类型 WPARAM定义为UINT_PTR LPARAM定义为LONG_PTR LONG_PTR是“用于指针精度的有符号长类型”。并且是一个带符号的32位或带符号的64位,具体取决于平台。 UINT_PTR是“无符号INT_PTR”,无符号32位或无符号64位,具体取决于平台。
  9. 来源http://www.pinvoke.net/default.aspx/user32.SendMessage

    如果你处于紧张状态...... SendInput Keys in Win32 & Win64 machines