2015-10-14 93 views
0

通过George Mamaladze阅读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是应用程序定义的或库定义的函数名称的占位符。 (有几个占位程序回调...)

LRESULT CALLBACK MouseProc(
    _In_ int code, 
     WPARAM wParam, 
    _In_ LPARAM lParam 
); 

是否HOOKPROC委托实例保持参照拉姆达,从而在乔治的代码MyProc的方法是什么?
下面是斯蒂芬·托布的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); 
} 

他们应该做到同样的事情更简单的方法。什么是乔治到这个扭曲的东西?解释可能有助于我的头晕或呼吸短促。

+0

乔治Mamaladze的解决方案看起来不可靠,他如何确保'hookProc'不会得到GC'ed?仅仅因为这个原因,我会更信任Stephen Toub的代码。 – Lukazoid

+0

@Lukazoid现在我没有说“通常”关于代码**,但快速浏览mamaladze代码并不能揭示这种机制,这是lambda的使用,我不知道 –

+0

这是一个合理的问题,可怜的标题,我建议你编辑 – Steve

回答

2

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

不,它不需要,hookProc可以尽快有资格垃圾收集函数退出,你的钩子将不再起作用,你需要在Stepen的代码,以保持像对委托的引用,从阻止它发生。

+0

静态回调不会做同样的事情吗? – code4life

+0

我使用简洁的代码像斯蒂芬的,但我想公开一个外部回调内的钩回调函数参数太像乔治 –

+0

@ code4life没有其实,我已经碰到它自己。如果你执行了'SetWindowsHookEx(hookId,MyProc,...',它实际上被编译成了'SetWindowsHookEx(hookId,new HookProcedure(MyProc),...',那么一旦SetWindowsHookEx返回,那个隐藏的委托就可以被垃圾收集。使用回调你会得到一个'CallbackOnCollectedDelegate'错误。请参见[这是我的旧回答](http://stackoverflow.com/questions/12878729/thread-hook-procedure-is-no-longer-called-after-在这个相同的API调用中,更多细节,请按-tab-several-times-why/19626866#19626866) –