Ваше LowLevelKeyboardProc
определение неверно.Изменитесь с
type LowLevelKeyboardProc = delegate of (int * IntPtr * IntPtr) -> IntPtr
на
type LowLevelKeyboardProc = delegate of int * IntPtr * IntPtr -> IntPtr
или еще лучше
type LowLevelKeyboardProc = delegate of int * nativeint * nativeint -> nativeint
или еще лучше
[<StructLayout(LayoutKind.Sequential)>]
type KBDLLHOOKSTRUCT =
val vkCode : uint32
val scanCode : uint32
val flags : uint32
val time : uint32
val dwExtraInfo : nativeint
type LowLevelKeyboardProc =
delegate of int * nativeint * KBDLLHOOKSTRUCT -> nativeint
Во всем вышеперечисленномВ случаях proc
потребуется использовать каррированную форму, а не кортежную форму.
Также обратите внимание, что вы должны добавить SetLastError = true
ко всем extern
ed-функциям, в документации которых говорится, что при вызове GetLastError
при сбое(что относится к GetModuleHandle
, SetWindowsHookEx
и UnhookWindowsHookEx
).Таким образом, если произойдет сбой (и вы должны проверять возвращаемые значения ...), вы можете просто вызвать Win32Exception
или позвонить Marshal.GetLastWin32Error
, чтобы получить правильную диагностику.
EDIT : просто для ясности, вот все сигнатуры P / Invoke, которые я успешно протестировал локально:
[<Literal>]
let WH_KEYBOARD_LL = 13
[<StructLayout(LayoutKind.Sequential)>]
type KBDLLHOOKSTRUCT =
val vkCode : uint32
val scanCode : uint32
val flags : uint32
val time : uint32
val dwExtraInfo : nativeint
type LowLevelKeyboardProc = delegate of int * nativeint * KBDLLHOOKSTRUCT -> nativeint
[<DllImport("kernel32.dll")>]
extern uint32 GetCurrentThreadId()
[<DllImport("kernel32.dll", SetLastError = true)>]
extern nativeint GetModuleHandle(string lpModuleName)
[<DllImport("user32.dll", SetLastError = true)>]
extern bool UnhookWindowsHookEx(nativeint hhk)
[<DllImport("user32.dll", SetLastError = true)>]
extern nativeint SetWindowsHookEx(int idhook, LowLevelKeyboardProc proc, nativeint hMod, uint32 threadId)
Также обратите внимание, что это будет работать одинаково, если вы предпочитаете значениесемантика для KBDLLHOOKSTRUCT
:
[<Struct; StructLayout(LayoutKind.Sequential)>]
type KBDLLHOOKSTRUCT =
val vkCode : uint32
val scanCode : uint32
val flags : uint32
val time : uint32
val dwExtraInfo : nativeint
type LowLevelKeyboardProc = delegate of int * nativeint * byref<KBDLLHOOKSTRUCT> -> nativeint