【发布时间】:2011-04-15 22:24:15
【问题描述】:
我正在尝试在 F# 应用程序中使用 P/Invoke 设置低级键盘挂钩。 Win32 函数SetWindowsHookEx 将HOOKPROC 作为其第二个参数,我将其表示为(int * IntPtr * IntPtr) -> IntPtr 的委托,类似于在C# 中的处理方式。调用该方法时,我收到一个MarshalDirectiveException 说明无法封送委托参数,因为
泛型类型不能被封送
我不确定泛型是如何涉及的,因为所有类型都是具体指定的。任何人都可以对此有所了解吗?代码如下。
编辑
这可能与 F# 编译器处理类型签名的方式有关 - 反射器表明委托 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)
【问题讨论】:
-
+1 用于尝试从 F# 调用/调用并传递委托。老实说,我不知道这是否可以做到。
-
我认为结果类型应该只是
int,而不是IntPtr。但我想这不会对错误消息产生影响......;建议:添加调用SetHook的代码,可能那里有问题? -
@wmeyer :
int而不是nativeint的返回类型在 64 位平台上会失败。 -
@Frédéric Hamidi :这是将回调传递给所有 .NET 语言的本机代码的标准;为此使用 F# 没什么特别的。
-
@Frédéric Hamidi:我承认,一开始并不明显。
delegate of (int * int) -> int定义一个采用实际Tuple<int, int>的一元委托,而delegate of int * int -> int定义采用两个ints 的二元函数。但是,后者必须与柯里化函数一起使用,即使它似乎使用元组语法。无论如何,前一个版本的不明显语义是导致 Ben 错误的原因,因为Tuple<int, nativeint, nativeint>显然是一个泛型。
标签: winapi f# delegates pinvoke