正如我在我的评论中所说keybd_event()
已弃用,由SendInput()
替代。但是,您收到PInvokeStackImbalance
异常的原因是因为函数声明中最后两个参数是错误的。
几乎所有Declare...Lib
的例子都是针对VB 6或更低版本设计的,例如Long
与VB.NET的Long
数据类型不一样。我建议你到总是寻找P/Invoke片段使用DllImport
attribute。如果找不到VB.NET版本,则可以查找C#代码片段,然后使用在线转换器转换它们。
要修复错误,最后两个参数应该是UInteger
和UIntPtr
。
Public Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As UInteger, ByVal dwExtraInfo As UIntPtr)
然而,正如我说的,建议坚持DllImport
:
<DllImport("user32.dll")> _
Public Shared Sub keybd_event(bVk As Byte, bScan As Byte, dwFlags As UInteger, dwExtraInfo As UIntPtr)
End Function
您可以检查pinvoke.net对于P/Invoke的片段。
要使用今天推荐的方法SendInput()
,你可以利用我的InputHelper
类:
Imports System.Runtime.InteropServices
Public NotInheritable Class InputHelper
Private Sub New()
End Sub
#Region "Methods"
#Region "PressKey()"
''' <summary>
''' Virtually presses a key.
''' </summary>
''' <param name="Key">The key to press.</param>
''' <param name="HardwareKey">Whether or not to press the key using its hardware scan code.</param>
''' <remarks></remarks>
Public Shared Sub PressKey(ByVal Key As Keys, Optional ByVal HardwareKey As Boolean = False)
If HardwareKey = False Then
InputHelper.SetKeyState(Key, False)
InputHelper.SetKeyState(Key, True)
Else
InputHelper.SetHardwareKeyState(Key, False)
InputHelper.SetHardwareKeyState(Key, True)
End If
End Sub
#End Region
#Region "SetKeyState()"
''' <summary>
''' Virtually sends a key event.
''' </summary>
''' <param name="Key">The key of the event to send.</param>
''' <param name="KeyUp">Whether to push down or release the key.</param>
''' <remarks></remarks>
Public Shared Sub SetKeyState(ByVal Key As Keys, ByVal KeyUp As Boolean)
Key = ReplaceBadKeys(Key)
Dim KeyboardInput As New KEYBDINPUT With {
.wVk = Key,
.wScan = 0,
.time = 0,
.dwFlags = If(KeyUp, KEYEVENTF.KEYUP, 0),
.dwExtraInfo = IntPtr.Zero
}
Dim Union As New INPUTUNION With {.ki = KeyboardInput}
Dim Input As New INPUT With {
.type = INPUTTYPE.KEYBOARD,
.U = Union
}
SendInput(1, New INPUT() {Input}, Marshal.SizeOf(GetType(INPUT)))
End Sub
#End Region
#Region "SetHardwareKeyState()"
''' <summary>
''' Virtually sends a key event using the key's scan code.
''' </summary>
''' <param name="Key">The key of the event to send.</param>
''' <param name="KeyUp">Whether to push down or release the key.</param>
''' <remarks></remarks>
Public Shared Sub SetHardwareKeyState(ByVal Key As Keys, ByVal KeyUp As Boolean)
Key = ReplaceBadKeys(Key)
Dim KeyboardInput As New KEYBDINPUT With {
.wVk = 0,
.wScan = MapVirtualKeyEx(CUInt(Key), 0, GetKeyboardLayout(0)),
.time = 0,
.dwFlags = KEYEVENTF.SCANCODE Or If(KeyUp, KEYEVENTF.KEYUP, 0),
.dwExtraInfo = IntPtr.Zero
}
Dim Union As New INPUTUNION With {.ki = KeyboardInput}
Dim Input As New INPUT With {
.type = INPUTTYPE.KEYBOARD,
.U = Union
}
SendInput(1, New INPUT() {Input}, Marshal.SizeOf(GetType(INPUT)))
End Sub
#End Region
#Region "ReplaceBadKeys()"
''' <summary>
''' Replaces bad keys with their corresponding VK_* value.
''' </summary>
''' <remarks></remarks>
Private Shared Function ReplaceBadKeys(ByVal Key As Keys) As Keys
Dim ReturnValue As Keys = Key
If ReturnValue.HasFlag(Keys.Control) Then
ReturnValue = (ReturnValue And Not Keys.Control) Or Keys.ControlKey 'Replace Keys.Control with Keys.ControlKey.
End If
If ReturnValue.HasFlag(Keys.Shift) Then
ReturnValue = (ReturnValue And Not Keys.Shift) Or Keys.ShiftKey 'Replace Keys.Shift with Keys.ShiftKey.
End If
If ReturnValue.HasFlag(Keys.Alt) Then
ReturnValue = (ReturnValue And Not Keys.Alt) Or Keys.Menu 'Replace Keys.Alt with Keys.Menu.
End If
Return ReturnValue
End Function
#End Region
#End Region
#Region "WinAPI P/Invokes"
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function SendInput(ByVal nInputs As UInteger, <MarshalAs(UnmanagedType.LPArray)> ByVal pInputs() As INPUT, ByVal cbSize As Integer) As UInteger
End Function
<DllImport("user32.dll")> _
Private Shared Function MapVirtualKeyEx(uCode As UInteger, uMapType As UInteger, dwhkl As IntPtr) As UInteger
End Function
<DllImport("user32.dll")> _
Private Shared Function GetKeyboardLayout(idThread As UInteger) As IntPtr
End Function
#Region "Enumerations"
Private Enum INPUTTYPE As UInteger
MOUSE = 0
KEYBOARD = 1
HARDWARE = 2
End Enum
<Flags()> _
Private Enum KEYEVENTF As UInteger
EXTENDEDKEY = &H1
KEYUP = &H2
SCANCODE = &H8
UNICODE = &H4
End Enum
#End Region
#Region "Structures"
<StructLayout(LayoutKind.Explicit)> _
Private Structure INPUTUNION
<FieldOffset(0)> Public mi As MOUSEINPUT
<FieldOffset(0)> Public ki As KEYBDINPUT
<FieldOffset(0)> Public hi As HARDWAREINPUT
End Structure
Private Structure INPUT
Public type As Integer
Public U As INPUTUNION
End Structure
Private Structure MOUSEINPUT
Public dx As Integer
Public dy As Integer
Public mouseData As Integer
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure
Private Structure KEYBDINPUT
Public wVk As UShort
Public wScan As Short
Public dwFlags As UInteger
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure
Private Structure HARDWAREINPUT
Public uMsg As Integer
Public wParamL As Short
Public wParamH As Short
End Structure
#End Region
#End Region
End Class
例如:
If condition = True Then
InputHelper.SetKeyState(Keys.Scroll, False) 'Key down.
Else
InputHelper.SetKeyState(Keys.Scroll, True) 'Key up.
End If
'keybd_event'已被弃用,所以是'声明。 ..Lib'。当前发送键盘/鼠标事件的方法是使用[**'SendInput()'**](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v = vs。 85)的.aspx)。看到我的键盘输入包装[**在这个答案**](http://stackoverflow.com/questions/39809095/why-do-some-applications-not-accept-some-sendkeys-at-some-times/39811061 #39811061)。 –
看看这个例子: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx 这是为numloc,但根据您应该使用KEYEVENTF_EXTENDEDKEY的信息。 第二:COndition的背后是什么?是这样的: GetKeyboardState((LPBYTE)&keyState);例如。获取当前的关键状态? 第三,您可以尝试使用SetInput而不是keybg_event,因为keybg_event被取代 – Kiko
如果函数被正确声明,则根本没有错误。 “Thrown”复选框在默认情况下不应该勾选任何异常,因为即使处理异常,它也会中断应用程序。 –