如何只捕获iexplore.exe的击键?

时间:2014-01-03 08:52:41

标签: c++ visual-studio dll

我的目标是在用户与Internet Explorer(iexplore.exe)交互时捕获用户的击键。

这是我的一个名为hook.dll的DLL的DLL代码。

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

extern "C" __declspec(dllexport)
LRESULT keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0) {
        std::cout << "nCode: " << nCode << "; wParam: " << wParam
                  <<" (" << char(wParam) << "); scan code: "
                  << ((lParam & 0xFF0000) >> 16)
                  << "; transition state: " << ((lParam & 0x80000000) >> 31)
                  << std::endl;
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    std::cout << "hinstDLL: " << hinstDLL
              << "; fdwReason: " << fdwReason
              << "; lpvReserved: " << lpvReserved << std::endl;

    return TRUE;
}

以下是main.exe的主程序代码:

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

int main(int argc, char **argv)
{
    HMODULE dll = LoadLibrary("hook.dll");
    if (dll == NULL) {
        std::cerr << "LoadLibrary error " << GetLastError() << std::endl;
        return 1;
    }

    HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "keyboardHook");
    if (callback == NULL) {
        std::cerr << "GetProcAddress error " << GetLastError() << std::endl;
        return 1;
    }

    HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);
    if (hook == NULL) {
        std::cerr << "SetWindowsHookEx error " << GetLastError() << std::endl;
        return 1;
    }

    MSG messages;
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    UnhookWindowsHookEx(hook);
}

我用这些命令编译这个项目:

vcvars32.bat
cl /LD hook.cc /link user32.lib
cl main.cc /link user32.lib

当我执行程序时,按下 A B C 键,我看到以下输出。

C:\>main
hinstDLL: 10000000; fdwReason: 1; lpvReserved: 00000000
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 0
nCode: 0; wParam: 65 (A); scan code: 30; transition state: 1
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 0
nCode: 0; wParam: 66 (B); scan code: 48; transition state: 1
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
nCode: 0; wParam: 67 (C); scan code: 46; transition state: 1

到目前为止,这一切都很好,但是这个程序可以捕获桌面上任何位置的按键。但我想只捕获在Internet Explorer上进行的那些击键。我相信我需要修改主程序中的SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);调用,并将Internet Explorer的线程ID作为此调用的第四个参数传递。你能帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

您有两种解决方案:

1 SetWindowsHookEx WH_KEYBOARD与TID一起使用。这并不容易,因为你必须使用一种机制来检测新线程。

2 对所有主题使用SetWindowsHookEx WH_GETMESSAGE。您必须过滤KeyBoard消息和进程名称。这更简单(除了,如果你的EXE是32,你会错过64位进程,或者反过来,除非你构建并运行两个EXE和两个DLL(32/64)。要点:您将能够轻松键入Chrome和Firefox。

答案 1 :(得分:0)

以下是基于manuell建议使用WH_GETMESSAGE的解决方案代码。

hook.cc中的DLL代码:

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

extern "C" __declspec(dllexport)
LRESULT myHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION) {
        std::ofstream outputTxt("C:\\out.txt",
                                std::ofstream::out | std::ofstream::app);
        PMSG msg = (PMSG) lParam;

        // Get PID of process
        DWORD pid;
        GetWindowThreadProcessId(msg->hwnd, &pid);

        // Get process name
        char filename[1024];
        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                               FALSE, pid);
        GetModuleBaseName(h, NULL, filename, sizeof filename);

        // Log details only if it is Internet Explorer
        if (msg->message == WM_KEYUP && strcmp(filename, "iexplore.exe") == 0) {
            outputTxt << "nCode: " << nCode << "; wParam: " << wParam 
                      << "; message: " << msg->message
                      << "; keycode: " << msg->wParam << " '"
                      << char(msg->wParam) << "'"
                      << "; filename: " << filename << std::endl;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    std::cout << "hinstDLL: " << hinstDLL
              << "; fdwReason: " << fdwReason
              << "; lpvReserved: " << lpvReserved << std::endl;

    return TRUE;
}

main.cc中的主程序代码:

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

int main(int argc, char **argv)
{
    HMODULE dll = LoadLibrary("hook.dll");
    if (dll == NULL) {
        std::cerr << "LoadLibrary error " << GetLastError() << std::endl;
        return 1;
    }

    HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "myHook");
    if (callback == NULL) {
        std::cerr << "GetProcAddress error " << GetLastError() << std::endl;
        return 1;
    }

    HHOOK hook = SetWindowsHookEx(WH_GETMESSAGE, callback, dll, NULL);
    if (hook == NULL) {
        std::cerr << "SetWindowsHookEx error " << GetLastError() << std::endl;
        return 1;
    }

    MSG messages;
    while (GetMessage(&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    UnhookWindowsHookEx(hook);
}

编译此项目如下。

vcvars32.bat
cl /D_WIN32_WINNT=0x0401 /LD hook.cc /link user32.lib /link psapi.lib
cl main.cc /link user32.lib

由于我的EXE是32位,我启动了32位Internet Explorer,点击地址栏并按下键 A B C 。这是我在C:\ out.txt。

中找到的结果
nCode: 0; wParam: 1; message: 257; keycode: 65 'A'; filename: iexplore.exe
nCode: 0; wParam: 1; message: 257; keycode: 66 'B'; filename: iexplore.exe
nCode: 0; wParam: 1; message: 257; keycode: 67 'C'; filename: iexplore.exe

启动64位Internet Explorer,并且做同样的事情在C:\ out.txt中没有产生任何结果。