C# 扩展回调函数?

C# 扩展回调函数?,c#,lambda,keyboard-hook,C#,Lambda,Keyboard Hook,通过阅读GeorgeMamaladze c#“全局鼠标键钩子”源代码,我试图了解一些代码是如何工作的。这是“科拉松”号 public delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam); private static Handle HookGlobal(int hookId, Callback callback) { HookProcedure hookProc = (code, param, l

通过阅读GeorgeMamaladze c#“全局鼠标键钩子”源代码,我试图了解一些代码是如何工作的。这是“科拉松”号

public delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam);

private static Handle HookGlobal(int hookId, Callback callback)
{
    HookProcedure hookProc = (code, param, lParam) => MyProc(code, param, lParam, callback);

    Handle handle = SetWindowsHookEx(
            hookId,
            hookProc,
            Process.GetCurrentProcess().MainModule.BaseAddress,
            0);
    return handle;
}

private static IntPtr MyProc(int nCode, IntPtr wParam, IntPtr lParam, Callback callback)
{            
    var callbackData = new CallbackData(wParam, lParam);
    bool continueProcessing = callback(callbackData);
    if (!continueProcessing) 
    { return new IntPtr(-1); }
    return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
WinApi函数SetWindowsHookEx设置的消息泵将使用消息数据调用MyProc方法

HHOOK WINAPI SetWindowsHookEx(
  _In_ int       idHook,
  _In_ HOOKPROC  lpfn,
  _In_ HINSTANCE hMod,
  _In_ DWORD     dwThreadId
);
根据MSDN,HOOKPROC类型定义了一个指向回调函数的指针。(示例…)MouseProc是应用程序定义或库定义函数名的占位符。(有几个占位符过程回调…)

hookProc委托实例是否保留对lambda的引用,从而在George的代码中保留对MyProc方法的引用?
下面是Stephen Taub的MSDN博客中的一个更简单的方法

private delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam);
private static HookProcedure procedure = Callback;
private static IntPtr _hookID = IntPtr.Zero;        

public static void SetHook()
{
    _hookID = SetWindowsHookEx(
        WH_KEYBOARD_LL,
        procedure,
        Process.GetCurrentProcess().MainModule,
        0);        
}

private static IntPtr Callback(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0)
    {
    }
    return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
他们应该实现同样的目标。乔治用这些扭曲的东西干什么?一个解释可能有助于缓解我的头晕或呼吸急促

hookProc委托实例是否在George的代码中保留对lambda的引用,从而保留对MyProc方法的引用


不,如果不是这样,
hookProc
可能有资格进行垃圾收集,只要函数退出并且您的钩子不再工作,您需要像Stepen的代码中那样保留对委托的引用,以阻止它发生。

George Mamaladze的解决方案看起来不可靠,他如何确保hookProc
不会被GC'ed?仅出于这个原因,我更相信Stephen Toub的代码。@Lukazoid现在我确实说了“一般”关于代码**但快速浏览mamaladze代码并不能揭示那种机制,这是lambda的使用我不知道这是一个合理的问题,标题很差,我建议你编辑一下,我看到了内存流失。其他人看到了吗?静态回调不会做同样的事情吗?我正在使用类似stephen的简洁代码,但我也想在hook回调函数参数中公开一个外部回调,如george@code4life不,事实上,我自己也遇到过。如果您确实执行了
SetWindowsHookEx(hookId,MyProc,…
),则实际编译为
SetWindowsHookEx(hookId,new HookProcedure(MyProc)),…
并且一旦SetWindowsHookEx返回,该隐藏委托可以被垃圾收集。如果SetWindowsHookEx尝试使用回调,则会出现
CallbackOnCollectedDelegate
错误。有关更多详细信息,请参阅同一API调用。@JediCommymullah您可以做的是拥有一个
静态字典
,其中包含callbacks in.当用户想要取消订阅时,你可以从字典中删除回调。@ScottChamberlain:啊,谢谢你提供的信息,很有意义!
private delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam);
private static HookProcedure procedure = Callback;
private static IntPtr _hookID = IntPtr.Zero;        

public static void SetHook()
{
    _hookID = SetWindowsHookEx(
        WH_KEYBOARD_LL,
        procedure,
        Process.GetCurrentProcess().MainModule,
        0);        
}

private static IntPtr Callback(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0)
    {
    }
    return CallNextHookEx(_hookId, nCode, wParam, lParam);
}