【问题标题】:Callback method is not called when using WinAPI WH_CALLWNDPROC hook使用 WinAPI WH_CALLWNDPROC 挂钩时不调用回调方法
【发布时间】:2021-07-31 03:29:06
【问题描述】:

我想在窗口移动时收到消息。

我开始编写一个简单的 C++ 控制台应用程序,它可以连接到 Windows 的默认记事本应用程序。 其中一部分包含以下代码设置钩子(不是全部三个,只有一个)

_hook = SetWindowsHookEx(WH_MOUSE, CallWndProc, _dllInstance, tid); //WORKS
_hook = SetWindowsHookEx(WH_KEYBOARD, CallWndProc, _dllInstance, tid); //WORKS
_hook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, _dllInstance, tid); //DOESNT WORK

所以基本上挂钩的过程是相同的,每种挂钩类型都使用相同的回调函数。 为什么它不适用于 WH_CALLWNDPROC? 应用 WH_CALLWNDPROC 时,钩子和其他钩子一样成功,但它根本不起作用。

这是回调函数

// The callback function
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
    std::cout << "callback " << counter++ << "\n";

    //This is a must
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

但是在设置这个钩子时永远不会调用 CallWndProc。

我什至尝试在 DLL 中调用 CallWndProc 函数,但这也不起作用,所以我将它完全从 DLL 中删除,现在它是一个空 DLL。即使它有效,对我来说也没用,因为我需要在我的应用程序中而不是在目标线程上处理消息。

任何提示?这是完整的代码

#include "Main.h"
#include <Windows.h>

#include <iostream>


/* Variable to store the HANDLE to the hook. Don't declare it anywhere else then globally
or you will get problems since every function uses this variable. */
HHOOK _hook;

// the dll instance
HINSTANCE _dllInstance;

//HOOKPROC _dllCallback;

int counter = 0;

// The callback function
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
    std::cout << "callback " << counter++ << "\n";

    //This is a must
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

// This functions installs a hook to a window with given title
int InstallHook(const wchar_t* title) {

    /* 1. Get window handle of given title */
    std::wcout << "INFO: Getting window handle for \"" << title << "\"...\n";
    HWND hwnd = FindWindow(NULL, title);
    if (hwnd == NULL) {
        std::cout << "ERROR: Could not find target window.\n";
        return -1;
    }
     
    /* 2. Get ThreadID (TID) of the window handle */ 
    std::wcout << "INFO: Getting TheadID (TID) of \"" << title << "\"...\n";
    DWORD pid = NULL; // If we dont know -> NULL
    DWORD tid = GetWindowThreadProcessId(hwnd, &pid);
    if (tid == NULL) {
        std::cout << "ERROR: Could not find target window.\n";
        return -2;
    }

    /* 3. Load in the DLL */
    std::wcout << "INFO: Loading the DLL\n";
    _dllInstance = LoadLibrary(TEXT("winhooks_dll.dll"));
    if (_dllInstance == NULL) {
        std::cout << "ERROR: Could not load DLL...\n";
        return -3;
    }

    /* 3.5 Get Callback function from dll*/
    //_dllCallback = (HOOKPROC)GetProcAddress(_dllInstance, "_wmProcCallback@12");
    //if (_dllCallback == NULL) {
    //  std::cout << "ERROR: Could not get Callback function from dll instance\n";
    //  return -4;
    //}

    /* 4. Install the hook and set the handle */
    std::wcout << "INFO: Setting the hook...\n";
    _hook = SetWindowsHookEx(WH_MOUSE, CallWndProc, _dllInstance, tid); // The local callback version
    //_hook = SetWindowsHookEx(WH_CALLWNDPROCRET, _dllCallback, _dllInstance, tid); // The dll callback function
    if (_dllInstance == NULL) {
        std::cout << "ERROR: Could not set hook handle\n";
        return -5;
    }

    return 0;
}

int main() {

    const wchar_t* title = L"Untitled - Notepad";

    if (InstallHook(title) != 0) {
        std::wcout << "ERROR: Could not install hook on " << title << " last error -> " << GetLastError() << "\n";
        system("pause");
        return 1;
    }

    std::wcout << "SUCCESS: Hook is successfully installed on " << title << "\n";
    std::wcout << "Running message loop..." << std::endl;

    MSG msg;
    while (GetMessage(&msg, NULL, 0,0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

【问题讨论】:

  • WH_CALLWNDPROC 挂钩过程必须驻留在被注入的 DLL 中。 WH_CALLWNDPROC 钩子在目标线程的消息循环中运行,而不是在您的应用程序线程中。您必须使用 IPC 将消息信息发送回您的主应用程序。
  • 有问题的应用程序是 32 位还是 64 位进程? DLL 是 32 位还是 64 位?挂钩另一个进程需要将 DLL 注入该进程。不能将 32 位 DLL 注入 64 位进程,反之亦然。
  • @RemyLebeau 一切都是 32 位的,我知道这一点。好的,所以我需要注入 dll 并从 dll 内部初始化钩子,对吗?但是 dll 注入是由我的应用程序中的 SetWindowsHookEx 完成的 - 所以我是否也需要在 dll 中使用它?实现我的目标的概念对我来说很不清楚......这样的事情真的需要IPC吗?只是为了获取窗口移动事件...?
  • 是的,实际的注入是由SetWindowHookEx()处理的,它需要DLL的HINSTANCE,以及​​DLL中的hook过程的指针。如果挂钩过程在另一个进程中运行,就像另一个进程中线程的消息挂钩的情况一样,挂钩过程不能驻留在您的主应用程序中。无论您是从 DLL 内部还是在主应用程序内部安装钩子都没有关系,因为无论哪种方式,SetWindowsHookEx() 都会在您的主应用程序的上下文中调用
  • 那么 HOOKPROC 函数呢? SetWindowsHookEx 使用来自 dll 的 HINSTANCE 和 HOOKPROC 回调函数作为函数指针。这是否意味着我需要调用 SetWindowsHookEx 两次才能实现它?无论如何,我会尝试一下。谢谢。

标签: c++ winapi hook


【解决方案1】:

首先,源平台(32位或64位)必须与目标平台匹配。(在我的64位机器上,记事本是64位的。)
其次,对于 DLL 中的钩子程序,不要通过 print 来验证它是否有效,与 std::out 相同。 DLL 无处打印其内容。以下代码使用文件流。

// The callback function
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION)
    {
        if (wParam > 0)
        {
            std::cout << "sent by the current thread wParam=" << wParam;
        }
        CWPSTRUCT* s = (CWPSTRUCT*)lParam;

        //have no
        std::cout << " Index=" << nwinhooksdll++ << " s->message=" << s->message << " s->hwnd=" << s->hwnd << " s->wParam=" << s->wParam << " s->lParam=" << s->lParam << "\n";
        //MessageBox(NULL,L"CallWndProc",L"CALLBACK",0);

        //works
        myfile << " Index=" << nwinhooksdll++ << " s->message=" << s->message << " s->hwnd=" << s->hwnd << " s->wParam=" << s->wParam << " s->lParam=" << s->lParam << "\n";
    }

    //This is a must
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

【讨论】:

    猜你喜欢
    • 2021-12-07
    • 2016-07-05
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    相关资源
    最近更新 更多