鉴于我有一个像这样定义的基类型: [AbstractClass]type HookBase(hookType: HookId, threadId: int) = let mutable hHook = IntPtr.Zero ... member this.SetHook() = // Set the hook using SetWindowsHookEx(...) ... hHook - hhk member
[<AbstractClass>] type HookBase(hookType: HookId, threadId: int) = let mutable hHook = IntPtr.Zero ... member this.SetHook() = // Set the hook using SetWindowsHookEx(...) ... hHook <- hhk member this.Unhook() = // Remove the hook hHook <- IntPtr.Zero
和这样的派生类型:
type ForegroundIdleHook(thread: uint32) as this = inherit HookBase(HookId.WH_FOREGROUNDIDLE, int thread) let hookCallback nCode wParam lParam = ... CallNextHookEx((* here has to be the hook's handle *), nCode, wParam, lParam) ...
因为我不希望每个都有SetHook()和Unhook()代码
类型(最后将有15种钩子类型),我想到使用基本类型.但是F#不支持受保护的成员,我现在有问题在派生类型中获取hHook并在基类型中设置回调.
我想到使用CallerMemberNameAttribute和预定义的方法来实现这个:
// Base type member this.SetCallback(callback: HookProc, [<CallerMemberName>] ?name: string) = ... member this.GetHHook([<CallerMemberName>] ?name: string) = ... // Derived type do this.SetCallback(this.Proc) member private this.Proc = HookProc(hookCallback)
在SetCallback的情况下,可以建立一个计数器以确保只有一个方法的调用,但这对GetHHook不起作用,因为可以在实例的生命周期中多次设置和取消设置挂钩.
此外,由于其他被调用者也可能与所需方法具有相同的名称,因此这种方式也不是万无一失,我也不想拥有这些方法的公共范围.
除了我的测试之外,似乎该属性不适用于F#,因为必须为参数提供显式默认值. (我在这里错过了什么吗?)
是否有更好的方法来获取钩子的句柄并设置回调而不是让基本类型具有15次所述方法?
编辑:如07.01所示,F#不支持CallerMemberName属性,因此使用它的选项不适用.
在派生类型中你需要什么句柄?仅适用于CallNextHookEx?然后根本不暴露它,而是让SetCallback接受IntPtr类型的函数 – > HOOKPROC:
// Base type member this.SetCallback(makeCallback: IntPtr -> HookProc) = let callback = makeCallback hHook // do whatever you're supposed to do with the callback // Derived type let hookCallback handle nCode wParam lParam = ... CallNextHookEx(handle, nCode, wParam, lParam) do this.SetCallback(fun handle -> HookProc(hookCallback handle))
必须有一个更好的设计,而不是只是复制OOP模式,但我不期待阅读有关Hooks API的信息.