我的环境详细信息:

  • 操作系统:Windows 7 Enterprise Service Pack 1(64位操作系统)
  • 编译器:Microsoft Visual Studio 2005(Microsoft(R)32位C / C++优化编译器版本14.00.50727.762 for 80x86)
  • 我的程序main.exe和hook.dll是32位
  • Internet Explorer(iexplore.exe)是64位
  • Chrome(chrome.exe)是32位

  • 我编写了一个名为main.exe的C++程序,该程序进行以下调用:
    HOOKPROC callback = (HOOKPROC) GetProcAddress(dll, "keyboardHook");
    HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, callback, dll, NULL);
    
    keyboardHook函数在一个名为hook.dll的DLL中定义。此功能记录控制台上的每个按键以及一个名为out.txt的文件。

    我执行以下实验。
  • 在命令提示符下执行main.exe。
  • 将Internet Explorer(64位)作为我的 Activity 窗口,然后在其上按A,B和C。
  • 将Chrome(32位)作为我的 Activity 窗口,然后按X,Y和Z。
  • 使命令提示我的 Activity 窗口,并按Ctrl + C杀死main.exe。

  • 我在控制台上仅看到以下输出。
    C:\lab\keyhook>main,exe
    hinstDLL: 10000000; fdwReason: 1; lpvReserved: 00000000
    ); scan code: 28; transition state: 1
    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
    nCode: 0; wParam: 17 (◄); scan code: 29; transition state: 0
    nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
    hinstDLL: 10000000; fdwReason: 2; lpvReserved: 00000000
    hinstDLL: 10000000; fdwReason: 0; lpvReserved: 00000001
    

    我在要登录的文件中仅看到以下输出。
    C:\lab\keyhook>type out.txt
    ); scan code: 28; transition state: 1
    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
    nCode: 0; wParam: 17 (◄); scan code: 29; transition state: 0
    nCode: 0; wParam: 67 (C); scan code: 46; transition state: 0
    

    您可以看到在控制台或日志文件中均未捕获在32位Chrome上进行的击键。

    为什么我的用32位C++编译器编译的32位程序能够成功捕获在64位iexplore.exe上进行的击键,但无法捕获在32位chrome.exe上进行的击键?

    MSDN上的SetWindowsHookEx documentation似乎表明我的32位程序应该只能捕获在其他32位程序上进行的击键。



    这是调用SetWindowsHookEx的主程序的完整代码。
    // Filename: 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, "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);
    }
    

    这是DLL代码。
    // Filename: hook.cc
    #include <iostream>
    #include <fstream>
    #include <windows.h>
    
    extern "C" __declspec(dllexport)
    LRESULT keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
    {
        std::ofstream outputTxt("out.txt", std::ofstream::out | std::ofstream::app);
        outputTxt << "nCode: " << nCode << "; wParam: " << wParam
                  <<" (" << char(wParam) << "); scan code: "
                  << ((lParam & 0xFF0000) >> 16)
                  << "; transition state: " << ((lParam & 0x80000000) >> 31)
                  << std::endl;
        outputTxt.close();
    
        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;
    }
    

    这就是我编译该项目的方式:
    vcvars32.bat
    cl /LD hook.cc /link user32.lib
    cl main.cc /link user32.lib
    

    这就是过程的样子。请参见chrome.exe和main.exe是32位进程,而iexplore.exe实例是64位进程。

    您能解释为什么我的观察结果与MSDN文档不匹配吗?

    最佳答案

    汉斯·帕桑(Hans Passant)对这个问题和this answer by manuell的评论帮助我理解和修复了我的代码。

    相对路径"out.txt"是所有困惑的根源。

    我的32位程序成功将其32位挂钩插入了32位Chrome。因此,该挂钩在Chrome的上下文中运行,而“out.txt”文件则写在Chrome的工作目录中。因此,在Chrome上作为 Activity 窗口进行的击键X,Y和Z记录在“C:\ Program Files(x86)\ Google \ Chrome \ Application \ 31.0.1650.63 \ out.txt”中。

    C:\>type "C:\Program Files (x86)\Google\Chrome\Application\31.0.1650.63\out.txt"
    nCode: 0; wParam: 88 (X); scan code: 45; transition state: 0
    nCode: 0; wParam: 88 (X); scan code: 45; transition state: 1
    nCode: 0; wParam: 89 (Y); scan code: 21; transition state: 0
    nCode: 0; wParam: 89 (Y); scan code: 21; transition state: 1
    nCode: 0; wParam: 90 (Z); scan code: 44; transition state: 0
    nCode: 0; wParam: 90 (Z); scan code: 44; transition state: 1
    

    此输出未出现在控制台中,因为没有控制台与Chrome关联。

    但是,我的32位程序无法将其32位挂钩插入到64位Internet Explorer中。结果,该钩子(Hook)在我的程序的上下文中执行,并且当它记录在64位Internet Explorer上进行的击键时,在程序的工作目录中创建了“out.txt”文件。此输出也记录在控制台上,因为有一个与我的程序关联的控制台。这就是您在我的问题中提到的内容。

    对我的代码的一个简单修复是将击键记录到绝对路径"C:\\out.txt"中,而不是hook.cc中的相对路径“C:\ out.txt”,这样我就可以看到在32位程序和64位程序上进行的击键位程序在同一文件中。

    关于c++ - 32位程序无法捕获在32位进程上进行的击键,但能够捕获在64位进程上进行的击键,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20910872/

    10-16 04:23