首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >全局CBT钩子从未被调用。

全局CBT钩子从未被调用。
EN

Stack Overflow用户
提问于 2014-10-28 15:18:52
回答 1查看 1.2K关注 0票数 2

我正在尝试开发一个应用程序,它可以在整个系统范围内创建和销毁顶级窗口。我做了一个代码来利用CBT的钩子。该解决方案包含两个项目,DLL和EXE。EXE项目具有对DLL项目的引用。钩子是从DLL中设置的。EXE项目中有一个消息循环。问题是CBT钩子不起作用。在VS调试器的帮助下,我发现钩子回调永远不会被调用,而来自SetWindowsHookEx的返回代码是非零的,这意味着钩子被设置了。什么是错误?我该怎么解决呢?

下面是一个很小的例子。DLL,main.cpp:

代码语言:javascript
复制
#include <windows.h>

typedef void(*DECODERPROC)(int code, WPARAM wParam, LPARAM lParam);

HINSTANCE hInst = nullptr;
HHOOK hHook = nullptr;
DECODERPROC fpDecoder = nullptr;

LRESULT CALLBACK cbtProc(int code, WPARAM wParam, LPARAM lParam) {
    // FIXME: never called
    if (code > 0 && fpDecoder) {
        fpDecoder(code, wParam, lParam);
    }
    return CallNextHookEx(hHook, code, wParam, lParam);
}

__declspec(dllexport) bool InstallHook(DECODERPROC decoder) {
    if (hHook) return false;
    fpDecoder = decoder;
    return (hHook = SetWindowsHookEx(WH_CBT, cbtProc, hInst, 0)) != NULL;
}

__declspec(dllexport) bool UninstallHook() {
    if (!hHook) return false;
    bool res = UnhookWindowsHookEx(hHook) != NULL;
    if (res) hHook = NULL;
    return res;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    hInst = reinterpret_cast<HINSTANCE>(hModule);
    return TRUE;
}

EXE,main.cpp

代码语言:javascript
复制
#include <iostream>
#include <locale>

#include <windows.h>
#include <fcntl.h>
#include <io.h>
using namespace std;

typedef void(*DECODERPROC)(int code, WPARAM wParam, LPARAM lParam);
__declspec(dllimport) bool InstallHook(DECODERPROC);
__declspec(dllimport) bool UninstallHook();

int main() {
    _setmode(_fileno(stdout), _O_U8TEXT);
    WNDCLASS windowClass = {};
    windowClass.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {
        if (message == WM_DESTROY)
            UninstallHook();
        return DefWindowProc(hWnd, message, wParam, lParam);
    };
    LPCWSTR windowClassName = L"Foobar";
    windowClass.lpszClassName = windowClassName;
    if (!RegisterClass(&windowClass)) {
        wcerr << L"Failed to register window class" << endl;
        return 1;
    }
    HWND messageWindow = CreateWindow(windowClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0);
    if (!messageWindow) {
        wcerr << L"Failed to create message-only window" << endl;
        return 1;
    }

    InstallHook([](int code, WPARAM wParam, LPARAM lParam) {
        wcout << L"Never called" << endl;
    });

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-28 18:52:15

如果在Windows 64位上运行,则需要32位和64位版本的DLL才能挂钩每个正在运行的进程。32位DLL不能连接64位进程,反之亦然.因此,您需要从32位进程调用SetWindowsHookEx()来挂起32位进程,从64位进程调用挂钩64位进程。

更重要的是,DLL的一个单独实例被注入到每个正在运行的进程中,因此在DLL的每个实例中,除了调用InstallHook()的实例之外,您的DLL回调指针都是空的。因此,您需要重新设计您的钩子,以便使用进程间通信(窗口消息、命名管道、邮件插槽、套接字等)与您的主EXE通信,您不能使用函数指针。

根据实际调试的进程,您可能不会看到cbtProc()被调用。如果正在调试主EXE进程,则一旦安装了钩子,代码就不会在EXE的进程中触发任何CBT活动,调试器也不会向您显示在其他进程中发生的任何CBT活动,这些活动不是它正在调试的。

根据您在钩子中实际要寻找的内容,您可以考虑使用SetWinEventHook(),因为它可以与DLL一起使用,也可以不使用DLL,而且它比SetWindowsHookEx()具有更灵活的过滤功能。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26611982

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档