2011-04-07 37 views
5

我正在C#中編寫鍵盤記錄程序,但在從鍵盤事件中調用我的鉤子方法時遇到了一些麻煩。我的代碼顯示正確,但由於某種原因,回調沒有發生。.NET應用程序中沒有調用低級別鍵盤鉤子

下面是相關代碼:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId); 

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); 

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
private static extern IntPtr GetModuleHandle(string lpModuleName); 

private const int WH_KEYBOARD_LL = 13; 
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam); 
private static IntPtr HookHandle = IntPtr.Zero; 

static void Main() 
{ 
    /* install low level global keyboard hook */ 
    HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, GetModuleHandle(null), 0); 

    /* every 60 seconds, process collected keystrokes */ 
    for (;;) 
    { 
     Thread.Sleep(60000); 
     SendKeyData(); 
    } 
} 

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) 
{ 
    /* code to handle key events would be here */ 

    return CallNextHookEx(HookHandle, nCode, wParam, lParam); 
} 

private static void SendKeyData() 
{ 
    /* code to send accumulated keystroke data to remote server would be here */ 
} 

SetWindowsHookEx調用返回的句柄(即不爲空),因爲它應該,所以它應該意味着它安裝,但是當我把一個斷點HookCallback ,它永遠不會達到。

任何人都可以請告訴我可能做錯了什麼?

+1

如果你註釋掉'for'塊,它會起作用嗎? – 2011-04-07 17:35:00

+0

不,如果我這樣做,過程就會立即結束。 – 2011-04-07 17:42:18

+2

使用Timer而不是無限循環可能是更好的做法。至少有一個定時器,你可以在必要時停止它。 – jlafay 2011-04-07 17:51:51

回答

4

看起來您正在編寫控制檯應用程序。這應該是一個表單應用程序,因爲您正在處理Windows事件。只需隱藏表格,它就可以工作。

作爲一個變通的控制檯應用程序,你可以調用Application.DoEvents()在循環:

for (;;) 
{ 
    Thread.Sleep(1); 
    Application.DoEvents(); //Process event queue 
    SendKeyData(); 
} 

請使用爲好,不邪惡。

+0

不要睡一會兒,那會超時。 45毫秒是一個快樂的數字。 Application.Run()更好。 – 2011-04-07 18:03:32

+0

非常感謝!來自你們兩個的答案的結合使我獲得了成功的結果。我沒有意識到我需要一個明確的消息循環。現在我的程序調用Application.Run()來做到這一點,並且通過BackgroundWorker使用單獨的線程完成關鍵數據的發送(以及通過同步隊列在兩個線程之間進行通信)。我將用工作代碼更新我的問題。 – 2011-04-07 18:40:42

+0

如果您需要使用sleep,請使用sleep(1)。這段代碼會延遲所有的鍵盤輸入,並且IMO建議使用@ 45ms,而450ms是不可接受的。正確的解決方案是阻塞消息分派,但不知道如何在C#中的控制檯應用程序中執行此操作,而無需直接調用winapi函數。 – CodesInChaos 2012-04-12 21:59:15

0

嘗試

GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName) 

更換的GetModuleHandle(空),看看如果這樣做的伎倆。請注意,從GetCurrentProcess()返回的Process對象和從MainModule返回的ProcessModule對象都是一次性的,因此您可能需要將它們聲明爲變量,然後手動處理它們;甚至更好,把他們放在一個using區塊。

+0

感謝您的回覆,但是這是沒有問題的 - 儘管我確實有與參數調用SetWindowsHookEx最初是一個問題,誤把線程ID的參數,以及時,我只需要對全局鉤子當前進程的模塊句柄。 – 2011-04-07 18:42:11

相關問題