繁体   English   中英

如何在 Win32 中使用 DLL 挂钩子类化另一个应用程序控件?

[英]How to subclass another application control using DLL hook in Win32?

我正在尝试使此示例正常工作,其想法是将记事本编辑控件颜色更改为红色:

dll

#include "stdafx.h"

#include <string>
#include <commctrl.h>
#pragma comment( lib, "comctl32.lib")

#pragma data_seg("SHARED")

HWND hWndNotepad = nullptr;

#pragma data_seg()
#pragma comment(linker, "/section:SHARED,RWS")

HINSTANCE hInst;
HHOOK hGetMsgHook;
BOOL bSubclassed = FALSE;

#define WM_NOTEPADMESSAGE WM_USER + 10

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        hInst = (HINSTANCE)hModule;
    }
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    {
        char out[64] = { 0 };
        sprintf_s(out, 63, "DLL_PROCESS_DETACH, bSubclassed: %i", (int)bSubclassed);
        OutputDebugStringA(out);

        if (bSubclassed)
        {
            RemoveWindowSubclass(hWndNotepad, SubclassProc, 0);
            bSubclassed = FALSE;
            hWndNotepad = nullptr;
        }
    }
    break;
    }
    return TRUE;
}

extern "C" __declspec(dllexport) BOOL CALLBACK SetHook(BOOL bInstall)
{
    if (bInstall)
    {
        hWndNotepad = FindWindowA("Notepad", NULL);
        if (hWndNotepad)
        {
            char out[256] = { 0 };

            hGetMsgHook = SetWindowsHookExA(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, hInst, 0);
            if (hGetMsgHook)
            {
                DWORD dwThreadId = GetWindowThreadProcessId(hWndNotepad, NULL);
                PostThreadMessageA(dwThreadId, WM_NOTEPADMESSAGE, 0, (LPARAM)hWndNotepad);

                sprintf_s(out, 255, "hWndNotepad: %08X - Thread Id : %08X", (UINT)hWndNotepad, dwThreadId);
            }
            else {
                sprintf_s(out, 255, "Error SetWindowsHookEx: %d", GetLastError());
            }

            OutputDebugStringA(out);
        }
        else
        {
            char out[] = "Notepad not found";
            OutputDebugStringA(out);

            return FALSE;
        }
    }
    else
    {
        if (hGetMsgHook)
            UnhookWindowsHookEx(hGetMsgHook);
    }
    return TRUE;
}

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    MSG* lpMsg;
    if (nCode >= 0)
    {
        lpMsg = (MSG*)lParam;
        if (lpMsg->message == WM_NOTEPADMESSAGE)
        {
            char out[128] = { 0 };
            sprintf_s(out, 127, "WM_NOTEPADMESSAGE - hWndNotepad : %08X", (UINT)hWndNotepad);
            OutputDebugStringA(out);

            bSubclassed = SetWindowSubclass((HWND)hWndNotepad, SubclassProc, 0, 0);

            if (!bSubclassed) {
                sprintf_s(out, 127, "Error SetWindowSubclass : %d", GetLastError());
                OutputDebugStringA(out);
            }
        }
    }
    return CallNextHookEx(hGetMsgHook, nCode, wParam, lParam);
}

LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    char out[32] = { 0 };
    sprintf_s(out, 31, "uMsg : %d", uMsg);
    OutputDebugStringA(out);

    switch (uMsg)
    {
    case WM_CTLCOLOREDIT:
    {
        SetDCBrushColor((HDC)wParam, RGB(255, 0, 0));
        return (INT_PTR)GetStockObject(DC_BRUSH);
    }
    break;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

主程序:


HINSTANCE hinstDLL = nullptr;
BOOL hookset = false;

typedef BOOL(*SetHookType)(BOOL);
SetHookType SetHook = nullptr;

DWORD WINAPI dllTest(LPVOID) {

    char out[128] = { 0 };

    sprintf_s(out, 127, "--- dllTest beg ---");
    OutputDebugStringA(out);

    hookset = !hookset;

    if(hinstDLL == nullptr) {
#if _WIN32 || _WIN64
    #if _WIN64
        hinstDLL = LoadLibraryA("F:\\projects\\_dll_hook\\x64\\Release\\hook.dll");
    #else
        hinstDLL = LoadLibraryA("F:\\projects\\_dll_hook\\Release\\hook.dll");
    #endif
#endif
        sprintf_s(out, 127, "DLL loaded");
        OutputDebugStringA(out);
    }

    if (hinstDLL == nullptr) {
        sprintf_s(out, 127, "Error loading dll: #%d", GetLastError());
        OutputDebugStringA(out);
        return 0;
    }

    if (SetHook == nullptr) {
        SetHook = (SetHookType)GetProcAddress(hinstDLL, "SetHook");
        if (SetHook == nullptr) {
            sprintf_s(out, 127, "Error getting address of dll.SetHook: #%d", GetLastError());
            OutputDebugStringA(out);
            return 0;
        }
        SetHook(hookset);
    }

    if (!hookset) {
        FreeLibrary(hinstDLL);
        hinstDLL = nullptr;
        SetHook = nullptr;
        sprintf_s(out, 127, "DLL freed");
        OutputDebugStringA(out);
    }

    Sleep(10000);  // <-- ONE POSSIBLE SOLUTION

    sprintf_s(out, 127, "--- dllTest end ---");
    OutputDebugStringA(out);

    return 0;
}

我在调用 dllTest 两次后得到的 output :

[13800] --- dllTest beg ---
[13800] DLL loaded
[13800] hWndNotepad: 002B0FAC - Thread Id : 00003B30
[13800] --- dllTest end ---
[13800] DLL_PROCESS_DETACH, bSubclassed: 0
[10356] WM_NOTEPADMESSAGE - hWndNotepad : 002B0FAC
[10356] DLL_PROCESS_DETACH, bSubclassed: 1
[13800] --- dllTest beg ---
[13800] DLL_PROCESS_DETACH, bSubclassed: 0
[13800] DLL freed
[13800] --- dllTest end ---

看起来 WM_NOTEPADMESSAGE 已发送到记事本 window 但未被 GetMsgProc 捕获。 这段代码可能有什么问题以及如何使它工作?

谢谢!

首先,回调不起作用的原因是你的DLL将被注入到目标进程中,其他进程无法访问主程序中的function地址。

然后,我可以重现您的问题(记事本背景无法更改)。 主程序在SetHook之后立即结束,系统可能会自动注销你的钩子,然后目标进程无法访问SubclassProc地址。 尝试在主程序中添加任何延迟,例如消息循环。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM