我试图在F#应用程序中使用P/Invoke设置低级键盘挂钩。Win32函数
SetWindowsHookEx
接受一个类型为 HOOKPROC
的参数作为其第二个参数,我将其表示为一个委托 (int * IntPtr * IntPtr) -> IntPtr
,类似于在C#中处理此问题的方式。调用该方法时,我遇到了一个 MarshalDirectiveException
异常,指出委托参数无法进行封送,因为:
通用类型不能进行封送
我不确定泛型是如何涉及其中的,因为所有类型都是具体指定的。有人能解释一下吗?以下是代码。
编辑
这可能与F#编译器处理类型签名的方式有关。Reflector指示委托 LowLevelKeyboardProc
是实现为接受类型为 Tuple<int, IntPtr, IntPtr>
的参数的方法,并且会有无法封送的通用类型。是否有某种方法可以解决这个问题,还是说 F# 函数根本就无法封送到本地函数指针?
let WH_KEYBOARD_LL = 13
type LowLevelKeyboardProc = delegate of (int * IntPtr * IntPtr) -> IntPtr
[<DllImport("user32.dll")>]
extern IntPtr SetWindowsHookEx(int idhook, LowLevelKeyboardProc proc, IntPtr hMod, UInt32 threadId)
[<DllImport("kernel32.dll")>]
extern IntPtr GetModuleHandle(string lpModuleName)
let SetHook (proc: LowLevelKeyboardProc) =
use curProc = Process.GetCurrentProcess ()
use curMod = curProc.MainModule
SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curMod.ModuleName), 0u)
int
,而不是IntPtr
。但我猜这不会对错误消息产生影响...建议:添加调用SetHook
的代码,也许有问题? - wmeyerint
而不是nativeint
将在64位平台上失败。 - ildjarndelegate of (int * int) -> int
定义了一个接受实际Tuple<int, int>
的一元委托,而delegate of int * int -> int
则定义了一个接受两个int
的二元函数。但是,即使它看起来使用了元组语法,后者也必须与柯里化函数一起使用。无论如何,前者版本的非明显语义是导致Ben错误的原因,因为Tuple<int, nativeint, nativeint>
明显是一个泛型。 - ildjarn