0

I'll preface this with saying that I am new to win32 programming.

I'm creating a global keyboard hook using a .dll, I have put in install and uninstall functions to handle the actual setting and removing of the keyboard hook.

#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
static HHOOK hk=NULL;
//static CMyFile *pLF;
#pragma data_seg()

HINSTANCE hins = NULL;

__declspec( dllexport ) LRESULT Install(){
    std::cout << "Installing" << std::endl;
    hk = SetWindowsHookEx(WH_KEYBOARD_LL,EventAnalysis::KeystrokeAnalysis::KeyboardCallback,hins,0);
    if(hk == NULL){
        std::cout << "Hook creation failed! - " << GetLastError() << std::endl;
    }
    return 0;
}


 __declspec(dllexport) BOOL CALLBACK UnInstall()
{
    std::cout << "UnInstalling" << std::endl;
    return UnhookWindowsHookEx(hk);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hins = (HINSTANCE) hModule;
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

So now that I have my .dll, I created a simple executable that loads the library and installs the hooks:

int _tmain(int argc, _TCHAR* argv[])
{
    auto funHandle = LoadLibrary(L"C:\\Users\\tprodanov\\Documents\\visual studio 2010\\Projects\\HaveFun\\Release\\HaveFun.dll");
    if(funHandle == NULL){
        std::cout << "Library load failed! - " << GetLastError() << std::endl;
    }

    auto Install = (LRESULT(*)()) GetProcAddress(funHandle, "?Install@@YAJXZ");
    if(Install == NULL){
        std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
    }
    Install();

    MSG Msg;

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

    auto Uninstall = (BOOL(*)()) GetProcAddress(funHandle, "?UnInstall@@YGHXZ");
    if(Uninstall == NULL){
        std::cout << "Procedure load failed! - " << GetLastError() << std::endl;
    }
    Uninstall();
    return 0;
}

What I find curious is that the behavior of my program is as expected in its current state (and also if instead of a message loop I just pop out a MessageBox() that waits for the user to click OK), but it doesn't work if I use std::cin.get() or an empty while loop. Can someone please explain why this is the behavior?

Also as a followup question - the KeyboardCallback function just prints to the console "Key Pressed".

LRESULT CALLBACK EventAnalysis::KeystrokeAnalysis::KeyboardCallback(int nCode, WPARAM wParam, LPARAM lParam){
    std::cout << "Key pressed" << std::endl;
    return CallNextHookEx(NULL,nCode,wParam,lParam);
}

I expected that this will be printed only when I press keys when focused on the console window, but even if I type in notepad the "Key Pressed" messages show up in my executable that called the Install function of the .dll. I don't understand this, since as far as I understood the dynamic library is loaded independently in every process, so every process has its own copy of the KeyboardCallback function and it will try to print to the foreground window's console.

4

1 回答 1

2

文档清楚地说明了正在发生的事情:

这个钩子在安装它的线程的上下文中被调用。通过向安装钩子的线程发送消息来进行调用。因此,安装钩子的线程必须有一个消息循环。

钩子是由你调用来安装的Install。因此,在进行该调用的同一线程中,您需要运行一个消息循环。

至于为什么显示消息框会影响事物,消息框通过运行模式消息循环来操作。并且该消息循环将发送钩子消息。

对于后续问题,文档再次给出了答案:

每当一个新的键盘输入事件即将发布到线程输入队列时,系统都会调用这个函数。

当它说发布到线程输入队列时,它意味着任何线程输入队列

或者在文档的注释中SetWindowsHookEx查看各种钩子类型的列表及其范围。被WH_KEYBOARD_LL列为全局挂钩。

另请注意,这WH_KEYBOARD_LL是一个低级挂钩,因此不会导致 DLL 被注入另一个进程。事实上,您的代码过于复杂。您根本不需要这里的 DLL。您可以通过调用SetWindowsHookEx从同一可执行文件中传递回调函数的可执行文件来完成这一切。

这是一个演示所有这些的最小示例程序:

#include <Windows.h>
#include <iostream>

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    std::cout << "Key pressed" << std::endl;
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main(int argc, char* argv[])
{
    std::cout << "Installing" << std::endl;
    HHOOK hk;
    hk = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
    MSG Msg;
    while (GetMessage(&Msg, NULL, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    std::cout << "UnInstalling" << std::endl;
    UnhookWindowsHookEx(hk);
    return 0;
}
于 2013-09-30T09:30:35.570 回答