6

I am trying to hook for example Notepad without sucess. Making a global hook seems to work fine.

Testing on XP SP2.

Edit: Amended code works now.

MyDLL code

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

HINSTANCE hinst;
#pragma data_seg(".shared")
HHOOK hhk;
#pragma data_seg()
//#pragma comment(linker, "/SECTION:.shared,RWS") compiler error in VC++ 2008 express

LRESULT CALLBACK wireKeyboardProc(int code, WPARAM wParam,LPARAM lParam) {  
    if (code < 0) {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    Beep(1000, 20);
    return CallNextHookEx(hhk, code, wParam, lParam);
}

extern "C" __declspec(dllexport) void install(unsigned long threadID) { 
    hhk = SetWindowsHookEx(WH_KEYBOARD, wireKeyboardProc, hinst, threadID);
}
extern "C" __declspec(dllexport) void uninstall() {
    UnhookWindowsHookEx(hhk); 
}

BOOL WINAPI DllMain(__in HINSTANCE hinstDLL, __in  DWORD fdwReason, __in  LPVOID lpvReserved) {
    hinst = hinstDLL;
    return TRUE;
}

My program

#include <Windows.h>

unsigned long GetTargetThreadIdFromWindow(char *className, char *windowName)
{
    HWND targetWnd;
    HANDLE hProcess;
    unsigned long processID = 0;

    targetWnd = FindWindow(className, windowName);
    return GetWindowThreadProcessId(targetWnd, &processID);
} 

int _tmain(int argc, _TCHAR* argv[]) {
    unsigned long threadID = GetTargetProcessIdFromWindow("Notepad", "Untitled - Notepad");
    printf("TID: %i", threadID);    

    HINSTANCE hinst = LoadLibrary(_T("MyDLL.dll")); 

    if (hinst) {
        typedef void (*Install)(unsigned long);
        typedef void (*Uninstall)();

        Install install = (Install) GetProcAddress(hinst, "install");
        Uninstall uninstall = (Uninstall) GetProcAddress(hinst, "uninstall");

        install(threadID);

        Sleep(20000);

        uninstall();
    }

    return 0;
}
s5804
  • 995
  • 3
  • 12
  • 14

1 Answers1

14

Three problems:

You're using the process ID when you should be using the thread ID.

Your HHOOK needs to go into shared memory:

#pragma data_seg(".shared")
HHOOK hhk = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")

You need to pass your HHOOK to CallNextHookEx:

return CallNextHookEx( hhk, code, wParam, lParam);
RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • 1
    GetWindowThreadProcessId() returns the thread ID you need (as its return value). Whatever you're doing with inline assembler and ReadProcessMemory is not necessary, and almost certainly not working. – RichieHindle May 05 '09 at 11:31
  • 2
    you also need to initialize `hhk` to `0` or it won't get shared properly – yoyoyoyosef Jun 16 '09 at 20:40
  • 1
    For what it's worth, the `HHOOK` argument to `CallNextHookEx` is ignored on all Windows versions later than Windows 95; see http://stackoverflow.com/questions/214022/how-to-correctly-use-setwindowshookex-callnexthookex for more information. – Frerich Raabe Feb 29 '12 at 07:53
  • Hi there Ricchie. My "Mainthread" creates the windows, I spawn another thread and do all my work. (This is because I am writing a plugin for my firefox, and plugins only allowed to run in seperate threads, not on "Mainthread"). I am setting up a hook from another thread. I was doing a `WH_MOUSE_LL` hook but it was catching events even when my app was not in focus. I tried `WH_MOUSE` when the thread id of the "Mainthread" and it would set up the listener, but on first mouse event (move etc) it crashes. I strongly suspect its becase my callback is setup in off thread? Do you think so too? – Noitidart Mar 23 '16 at 18:23
  • I am not using a DLL. I define a callback in the "off mainthread" and then use that for the hook. It worked wonderfully for the `LL`. But my goal is to only get events while my app is focused. Is there anyway to setup a `WH_MOUSE` hook with callback from a spawned thread for the windows using the "Mainthread" id? – Noitidart Mar 23 '16 at 18:25
  • 1
    @Noitidart: A thread-specific WH_MOUSE hook must be defined in a DLL, which will be injected into, and called from the context of, the application receiving the mouse event. A WH_MOUSE_LL hook doesn't need to go in a DLL but can only be system-wide. One solution might be to use WH_MOUSE_LL and then use WindowFromPoint() and GetWindowThreadProcessId() to ignore messages that aren't for your target thread. – RichieHindle Mar 23 '16 at 22:07
  • Ah thanks very much for your answer there. I'll investigate the winwo from point thing. :) – Noitidart Mar 23 '16 at 23:28
  • @RichieHindle - I just wanted to make sure - I am wanting to only hook my own application for `WH_MOUSE`, even for this I will need a DLL? – Noitidart Mar 25 '16 at 05:01
  • 1
    @Noitidart: In the case where you're hooking your own thread, I don't think you need a DLL, but I'm not 100% sure. In the case where you're hooking a different thread in the same process, I also don't know. – RichieHindle Mar 26 '16 at 07:50
  • Thanks very much for that info @RichieHindle! :) – Noitidart Mar 26 '16 at 12:18