2014-11-21 96 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