user2047610
user2047610

Reputation: 136

SetWindowsHookEx(WH_KEYBOARD) not working with thread ID

I have a dll that gets called by a process and now I would like to implement an input check in the dll to react on certain inputs that occur in the application.

SetWindowsHookEx() with a KeyboardProc function seemed like a possible solution so I implemented it.

This is roughly how the code in the dll looks like:

static HHOOK hhk = NULL;
LRESULT CALLBACK keyboardProc(int code, WPARAM wParam, LPARAM lParam)
{  
    if(code == HC_ACTION && ((DWORD)lParam & 0x80000000) == 0)  // if there is an incoming action and a key was pressed
    {
       switch(wParam)
       {
       case VK_SPACE:
          printf("Space was pressed\n");
          break;
       }
    }
    return CallNextHookEx(hhk, code, wParam, lParam);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    if(ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        if(AllocConsole()){
            freopen("CONOUT$", "w", stdout);  // redirect output to console for debugging
        }
        printf("Dll loaded, lastError = %i\n", GetLastError());
        printf("lastError = %i\n", GetLastError());
        // sidenote: for some reason the first GetLastError() returns 0 while the second one returns 6 (invalid handle)

        hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, GetCurrentThreadId());
    }
    else if (ul_reason_for_call == DLL_PROCESS_DETACH)
    {
        printf("\nCleaning up...");
        FreeConsole();
        UnhookWindowsHookEx(hhk);
    }
    return TRUE;
}

However nothing happens (or gets printed) in the Console window when I press any key. It doesn't even seem like the keyboardProc function is accessed at any time.

It does work though when I pass NULL instead of GetCurrentThreadId() to SetWindowsHookEx(). But this causes the hook to work globally meaning that whenever I press a key in another application, a Console window pops up (because the dll gets called again) and he checks for key inputs there. Obviously this is not desired and I would like to make this work with only the process that originally called the dll.

I already checked if GetCurrentThreadId() returns a valid ID and it seems to be indeed the main thread ID of the process that initially called the dll (checked with Process Explorer).

So now my question is what could be the problem and more importantly, what can I do to make it working?

Upvotes: 1

Views: 1987

Answers (1)

Yi You
Yi You

Reputation: 1

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

uint process_id;
uint thread_id = GetWindowThreadProcessId(windowHandle, out process_id);
hhook = SetWindowsHookEx(WH_KEYBOARD, a_KeyboardProc, hInstance, 0);

I have used the code above to get the main thread_ID for a certain process. The good part is, the SetWindowsHookEx function gives a logical output. Unfortunately, the bad part is, if a key is pressed in the thread that has been hooked, the thread stops working.

In specific, the idHook parameter of SetWindowsHoookEx function was set to 2 (instead of 13) in my case for non-low-level keyboard events. It seems, at least to me, that LL corresponds to low-level, where keyboardProc should come with a WH_KEYBOARD instead of WH_KEYBOARD_LL.

I am not sure at this point how my response would be related to your question. Hopefully, we get what we need through discussion.

Upvotes: -1

Related Questions