首页 > 解决方案 > 使用钩子向 explorer.exe 主窗口发送消息会导致崩溃?

问题描述

我正在尝试使用我从中获取的信息在WH_CALLWNDPROC窗口上设置一个钩子,然后发送一条消息。但根据我使用的情况,它会使窗口崩溃。HWNDWindowFromPointWM_USER+xHWND

让我解释一下场景:

HWND通过该功能时,您有时会获得WindowFromPoint其中一个孩子而不是主窗口。

使用 spy++ 中的 Finder 工具可以很好地可视化

HWND

所以我只是得到了窗口

wcout << "INFO: Waiting 1 second before first hwnd...\n";
this_thread::sleep_for(chrono::milliseconds(1000));
HWND targetHwnd = getHwndFromMousePos(); //Gets hwnd from mouse pos with WindowFromPoint
outHwndData(targetHwnd);
DWORD targetPID;
DWORD targetTID = GetWindowThreadProcessId(targetHwnd, &targetPID);

然后使用 dll 的导出函数设置挂钩。

hook = setHook(targetTID); //hook is the global HHOOK and setHook is a exported function in a dll
if (hook == NULL) {
    cout << "ERROR: Could not set hook\n";
    return 1;
}

dll里面的函数是这样的

extern "C" __declspec(dllexport) HHOOK __stdcall setHook(DWORD targetTid) {
    return SetWindowsHookEx(WH_CALLWNDPROC, wmProcCallback, hInst, targetTid);
}

什么时候targetHwnd是孩子HWND,我挂钩,发送消息->工作正常

但是什么时候targetHwnd是上层HWND(绿色标记的),我钩住它,发送一条消息->它崩溃了。

在此处输入图像描述

所以最后工作,但如果它是上部(绿色标记一个)SetWindowsHookEx,我无法向找到的窗口发送任何消息。HWND为什么呢?

这个完整的演示代码将等待 1 秒钟,然后再获取HWND. 通过将鼠标悬停在 explorer.exe 窗口的标题栏上,您可以获得HWND导致崩溃的原因。

申请代码:

//This is the app
#include <Windows.h>
#include <iostream>
#include <thread>

using namespace std;

typedef HHOOK(WINAPI* DLLFUNC_SETHOOK) (DWORD);

HINSTANCE dllInstance;
DLLFUNC_SETHOOK setHook;

HHOOK hook;

HWND getHwndFromMousePos() {
    POINT cursorPos;
    if (GetCursorPos(&cursorPos) == FALSE) {
        cout << "ERROR: Could not get Cursor position...\n";
        return NULL;
    }
    HWND wnd = WindowFromPoint(cursorPos);
    if (wnd == NULL) {
        cout << "ERROR: No window found on this point\n";
        return NULL;
    }
    return wnd;
}


int main() {

    wcout << "INFO: Waiting 1 second before first hwnd...\n";
    this_thread::sleep_for(chrono::milliseconds(1000));
    HWND targetHwnd = getHwndFromMousePos();

    wcout << targetHwnd << endl;
    DWORD targetPID;
    DWORD targetTID = GetWindowThreadProcessId(targetHwnd, &targetPID);

    dllInstance = LoadLibrary(L"DLL1.dll");
    setHook = (DLLFUNC_SETHOOK)GetProcAddress(dllInstance, "setHook");
    if (dllInstance == NULL) {
        cout << "ERROR: dllInstance is NULL\n";
        return 1;
    }
    if (setHook == NULL) {
        cout << "ERROR: setHook function is NULL\n";
        return 1;
    }

    hook = setHook(targetTID);
    if (hook == NULL) {
        cout << "ERROR: Could not set hook\n";
        return 1;
    }

    cout << "INFO: Hooked successfully\n";

    //Works only when targetHwnd is a children
    SendMessage(targetHwnd, WM_USER + 1, 0, 0); //This causes the crash

    cin.ignore();

    BOOL success = UnhookWindowsHookEx(hook);
    if (success == FALSE) {
        cout << "ERROR: Could not unhook\n";
    }
    else {
        cout << "INFO: Unhooked hook. Exiting...\n";
    }
}

DLL(DLL1):

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <fstream>

extern HINSTANCE hInst;
extern std::wofstream logfile;
extern "C" __declspec(dllexport) HHOOK __stdcall setHook(DWORD targetTid);

HINSTANCE hInst;
std::wofstream logfile;

BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    hInst = hModule;
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH: { 
            logfile.open("D:\\projects\\crashDemo\\log.txt"); //run "Get-Content -Path "log.txt" -Wait" in Powershell for realtime logs
            break;
        }
        case DLL_THREAD_ATTACH: break;
        case DLL_THREAD_DETACH: break;
        case DLL_PROCESS_DETACH: {
            logfile.close();
            break;
        }
    }
    return TRUE;
}

LRESULT CALLBACK wmProcCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= HC_ACTION) {
        PCWPSTRUCT cwpStruct = (PCWPSTRUCT)lParam;
        switch (cwpStruct->message) {
        case WM_USER + 1:
            logfile << "WM_USER+1 Message received" << std::endl;
            break;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

extern "C" __declspec(dllexport) HHOOK __stdcall setHook(DWORD targetTid) {
    return SetWindowsHookEx(WH_CALLWNDPROC, wmProcCallback, hInst, targetTid);
}

编辑:我确实调试过了。看起来 dll 一切正常。它会加载并按wmProcCallback应有的方式多次调用。我WM_USER+1也被识别,但在处理完所有消息后,wmProcCallback它会立即关闭窗口并留下以下错误消息。

在此处输入图像描述

所以我总共收到 4 条错误消息:

  1. & 2。An outgoing call cannot be made since the application is dispatching an input-asynchronous call

  2. The operation is not permitted because the calling application is not the owner of the data on the clipboard.

  3. Unspecified error

有人知道其中哪些是相关的,因为我不知道这些错误中的任何一个吗?现在要做一些研究。如果有人可以帮助解决这个问题,那就太好了。

标签: c++winapihookhwnd

解决方案


简单修复,不要使用 WM_USER+1 :)


推荐阅读