2014-11-21 27 views
1

我試圖做一個簡單的鍵盤測試,但我的程序沒有按預期工作,我不知道爲什麼。如何添加一個鉤子到鍵盤(HookProc)

在我的程序中,我有一個低級別的鍵盤掛鉤,並附加一個簡單的過程。該過程只是打開/創建一個文件並寫入「Hello World」,然後關閉。但是它不會創建該文件,可能是因爲我的進程不正確,或者因爲我的鉤子沒有正確建立。

代碼:

#include<windows.h> 
#include<stdio.h> 
#include <iostream> 
#include <fstream> 

using namespace std; 

LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam){ 
    ofstream myfile; 
     myfile.open ("[PATH]/example.txt"); 
     myfile << "Hello world";//((KBDLLHOOKSTRUCT *)lParam)->vkCode 
    myfile.close(); 
    return CallNextHookEx(NULL,code,wParam,lParam); 
} 

int main(void){ 
    HINSTANCE hInst = NULL; 
    HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hInst, 0); 
    printf("HHOOK is not null: %s\n", (hHook != NULL) ? "True" : "False"); 
    char q; 
    for (cout << "q to quit\n"; q != 'q'; cin >> q); 

    printf("Successfully unhooked: %s", UnhookWindowsHookEx(hHook) ? "True" : "False"); 
} 

解決方案我需要一個消息循環添加到主功能:

LPMSG Msg; 
while(GetMessage(Msg, NULL, 0, 0) > 0) 
{ 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
} 
+0

檢查調用'SetWindowsHookEx'的結果。從MSDN引用:「如果函數失敗,返回值爲NULL。要獲得擴展錯誤信息,請調用GetLastError。」 – bialpio 2014-11-21 20:56:06

+0

它不爲空,我會更新代碼,使其包含檢查 – Alter 2014-11-21 20:59:20

+0

您的解決方案有一個大內存問題!您正在使用指向MSG的指針,但您沒有分配內存來存儲它。你最好使用:MSG Msg;並將它的指針傳遞給每個函數(即&Msg) – cabbi 2014-11-22 05:52:26

回答

4

THRE是兩種掛鉤:

全局鉤子
應該放置全局鉤子程序到一個單獨的DLL中,然後在你的主進程中加載​​鉤子dll並且它的鉤子程序並且設置鉤子。

一個全局掛鉤監視消息爲同一桌面上的所有線程爲 調用線程。一個線程專有的鉤子只監視單個線程中的消息 。可以在與調用線程 相同的桌面中的任何應用程序的 上下文中調用全局掛鉤過程,因此過程必須位於單獨的DLL模塊中。

那麼說:KeyboardProc進入一個單獨的DLL(例如myhookdll.dll)。
在你的過程中,你做這樣的事情:

HOOKPROC hkprc; 
static HINSTANCE hhookDLL ; 
static HHOOK hhook ; 

hhookDLL = LoadLibrary(TEXT("c:\\...\\myhookdll.dll")); 
hkprc = (HOOKPROC)GetProcAddress(hhookDLL, "KeyboardProc"); 

hhook = SetWindowsHookEx( 
        WH_KEYBOARD, 
        hkprc, 
        hhookDLL, 
        0); 

這裏有很好的參考:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644960(v=vs.85).aspx

線程級鉤子
這個特定的「WH_KEYBOARD_LL」掛接在線程級別,它不需要一個單獨的DLL。

線程專用的 鉤子程序僅在關聯線程的上下文中被調用。 如果應用程序爲其自己的 線程之一安裝鉤子過程,則鉤子過程可以與應用程序代碼的其餘部分位於同一個模塊中,也可以位於DLL中。如果應用程序 爲不同應用程序的線程安裝鉤子程序,則該程序必須位於DLL中。有關信息,請參閱Dynamic-Link 庫。

但線程級鉤子需要一個消息泵:

這個鉤子被稱爲在安裝它的線程的上下文。 該呼叫是通過向安裝了 掛鉤的線程發送消息來完成的。因此,安裝該鉤子的線程必須有一個 消息循環。

這裏一個基本的消息循環:

while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) 
    { 
    if(bRet == -1) 
    { 
     // Handle Error 
    } 
    else 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
    } 
+0

我正在通過這個工作,試圖使它適應我的代碼,你知道如何擺脫消息循環而不手動關閉這個過程嗎?我嘗試在while循環中放入一個計數器,但它不起作用 – Alter 2014-11-21 22:05:23

+0

如果'GetMessage'檢索到WM_QUIT消息,則返回值爲零,循環結束。 – cabbi 2014-11-21 22:21:17

+0

也許我誤解了你的問題,對不起。 'GetMessage'是一種阻塞方法(即在收到消息之前不會返回)。如果你想在消息循環中使用計數器或超時,確實使用'PeekMessage'。 – cabbi 2014-11-21 22:24:21