Как я сказал в своем комментарии keybd_event()
устарел и заменен на SendInput()
. Однако причина, по которой вы получаете исключение PInvokeStackImbalance
, заключается в том, что последние два параметра неверны в объявлении вашей функции.
Почти все Declare...Lib
примеры из там предназначены для VB 6 или ниже, где, например, Long
не такой же, как тип данных Long
Vb.net в. Я советую вам всегда Ищите фрагменты 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' устарела, и поэтому' Declare. ..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, но в соответствии с info вы должны использовать KEYEVENTF_EXTENDEDKEY. Во-вторых: что стоит за CO? Это что-то вроде: GetKeyboardState ((LPBYTE) & keyState); Например. для получения текущего состояния ключа? В-третьих, вы можете попробовать использовать SetInput вместо keybg_event, так как keybg_event заменяется – Kiko
Если функция была объявлена правильно, ошибок не должно быть вообще. По умолчанию флажок «Брошенный» не следует отмечать для каких-либо исключений, так как он нарушит приложение, даже если обработано исключение. –