SetWindowsHookEx(WH_KEYBOARD) calling hooked dll again when unfocused

Hi, so I have a dll that gets called by the main process and I would like to check for any keyboard input that is happening in the main process within the dll by using the SetWindowsHookEx function.

This is roughly how the dll looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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;
    default:
      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, NULL);
  }
  else if (ul_reason_for_call == DLL_PROCESS_DETACH)
  {
    printf("\nCleaning up...");
    FreeConsole();
    UnhookWindowsHookEx(hhk);
  }
  return TRUE;
}

Now when I start up the program, everything is loading fine and it even works like I want it when I keep the program focused (which means every time I press "Space", the message gets printed in that console).

However for some reason when I switch the focus to another program or even to the console where the output is printed then every time I press a key, the DllMain() function in the hook is called with ul_reason_for_call = DLL_PROCESS_ATTACH.

That means when I press any key somewhere else, a new console window is allocated and when I put the focus on the window from where I previously pressed that key and press "Space" there, the message is written in the newly created console.

So my question is, why is this happening (or what am I doing wrong) and how do I fix it?
SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, NULL); sets a global hook. This means that the hook is assigned to all applications running on the desktop.
By setting the last parameter of SetWindowsHookEx you can hook only one thread.

You can do something like this:
1
2
3
DWORD thread_id;
GetWindowThreadProcessId(FindWindowA(NULL,"set Window title you want to hook here"),&thread_id);
 hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule,thread_id);
Thanks for the answer, I wasn't aware that SetWindowsHookEx is global if no thread ID is specified.

However since the program I want to use this with has in most cases a different window title I would prefer a different solution to get its thread ID.

I was thinking of using the process ID that called the dll to get a thread ID that I can pass, but is something like that even possible to do?
Because even after a somewhat quick search I wasn't able to find anything in that direction...
You can check whether the process ID matches the process ID of the target app. I don't think this is the best solution but it should work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <tlhelp32.h>
unsigned GetProcessIdByName(const char *process_name)
{
  HANDLE hProcessSnap;
  PROCESSENTRY32 pe32;

  hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);

  if(hProcessSnap==INVALID_HANDLE_VALUE)
      return 0;

  pe32.dwSize=sizeof(PROCESSENTRY32);

  if(!Process32First(hProcessSnap,&pe32))
      return 0;

  do
    {
      if(strcmp(pe32.szExeFile,process_name)==0)
        return pe32.th32ProcessID;

    }
  while(Process32Next(hProcessSnap,&pe32));

  return 0;
}

// ....

// inside "  if(ul_reason_for_call == DLL_PROCESS_ATTACH)"
 if(GetProcessIdByName("target_process_name.exe")!=GetCurrentProcessId())
    return false;


Another way would be to enumerate all threads of process and set hook only for them.
Last edited on
Actually I was looking for a way to get the thread ID (of the main thread if there are multiple threads) by using only the process ID.

And after some more searching I also found a code snippet which seems to do the job -> http://www.codeproject.com/Questions/78801/How-to-get-the-main-thread-ID-of-a-process-known-b (first solution)

Though that seems to be simply the same ID than GetCurrentThreadId(), is that correct? By using your code sample I was at least able to verify that GetCurrentProcessId() returns the wanted value.

Anyway, when I use that thread ID like this hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, GetCurrentThreadId()); it won't work anymore. Nothing is printed in the console when I hit "Space" and after a short test it doesn't even seem like he is accessing the keyboardProc code.

So what could be the problem now?
Last edited on
Topic archived. No new replies allowed.