How to record/output other programs messages from a hooked DLL in Win32?

user42 121 Reputation points
2021-01-08T06:45:49.607+00:00

I have a Win32 GUI app where a thread starts upon pressing a button like so:

switch (wmId)
        {
            case int(BTN::Test) :
                CreateThread(NULL, 0, dllTest, &hWnd, 0, NULL);
...

HHOOK hhookSysMsg = nullptr;
HINSTANCE hinstDLL = nullptr;

DWORD WINAPI dllTest(LPVOID) {
    HOOKPROC hkprcSysMsg;

    hinstDLL = LoadLibraryA("xxx\\_dll_hook\\x64\\Release\\hook.dll");

    if (hinstDLL == NULL) {
        prnt("Error loading dll: #%d", PV, GetLastError()); 
        return 0;
    }

    hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
    if (hkprcSysMsg == NULL) {
        prnt("Error getting address of dll.SysMessageProc: #%d", PV, GetLastError());
        return 0;
    }

    hhookSysMsg = SetWindowsHookExA(
        WH_CALLWNDPROC,
        hkprcSysMsg,
        hinstDLL,
        0);

    if (hhookSysMsg == NULL) {
        prnt("Error hooking dll.SysMessageProc: #%d", PV, GetLastError());
        return 0;
    }

    S leep(5000);

    UnhookWindowsHookEx(hhookSysMsg);

    FreeLibrary(hinstDLL);

    return 0;
}

and here is the DLL code:

std::unordered_map<int, std::string> map;

void loadMsg() {
    std::fstream stream("xxx\\msg.txt");
    if (stream.is_open()) {
        std::string line;
        while (std::getline(stream, line)) {
            auto index = line.find(' ');
            if (index != std::string::npos)
                map.insert(std::make_pair(std::stoi(line.substr(0, index)), line.substr(index + 1)));
        }
        stream.close();
    }
}

INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {

    switch (Reason) {
    case DLL_PROCESS_ATTACH:
        OutputDebugStringA("DLL attach function called");
        loadMsg();
        break;
    case DLL_PROCESS_DETACH:
        OutputDebugStringA("DLL detach function called");
        break;
    case DLL_THREAD_ATTACH:
        OutputDebugStringA("DLL thread attach function called");
        break;
    case DLL_THREAD_DETACH:
        OutputDebugStringA("DLL thread detach function called");
        break;
    }

    return TRUE;
}

extern "C" __declspec(dllexport) LRESULT CALLBACK SysMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam);

    if (nCode == HC_ACTION) {

        CWPSTRUCT* pCWP = (CWPSTRUCT*)lParam;

        HWND hWnd = pCWP->hwnd;

        char wclass[256]; wclass[0] = 0;
        if (GetClassNameA(hWnd, wclass, 255) != 0) {
            std::string msg = map[pCWP->message];

            if (1) // || strcmp(wclass, "SysHeader32") == 0 || strcmp(wclass, "SysListView32") == 0 || msg == "WM_NOTIFY") {
                char out[256]; out[0] = 0;
                sprintf_s(out, 255, "class: '%s', msg: %s %08X\n", wclass, msg.c_str(), pCWP->message);
                OutputDebugStringA(out);
            }
        }
    }


    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

This code works but it never prints out (in DebugView or MSVS Debug Output) messages sent for other open programs, only this program own messages.

If I replace OutputDebugStringA with an output to a file, the target program (like Notepad where I open menus or type text) and explorer.exe often crash or the target program freezes. But then if I look at the file, I can see that messages for different programs were recorded there before crash.

So why it might be happening and what is the right way to record messages in this case, so it's fast and captures messages for other programs, like it's done in Spy++ ?

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,585 questions
{count} votes

Accepted answer
  1. Castorix31 84,471 Reputation points
    2021-01-08T09:41:39.24+00:00

    You can see the old MSDN application Hooks32, which still works on my OS (Windows 10, 1909)
    I had re-compiled it with VS 2015 : Hooks32 Source
    Hooks32.jpg


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.