2015-10-14 124 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) –