【问题标题】:SetWindowsHookEx not calling my callback?SetWindowsHookEx 没有调用我的回调?
【发布时间】:2012-12-13 16:52:27
【问题描述】:

好吧,我尝试了不同的解决方案来解决我的问题,但它不起作用。

我调用 SetWindowsHookExA,然后当我按下一个键时,消息框不显示。怎么办?

这是我的代码(这是一个由程序加载的另一个 DLL 加载的 DLL):

#include <Windows.h>

HINSTANCE gl_hThisInstance = NULL;
HHOOK hHook = NULL;

LRESULT CALLBACK KeyHit(int code,WPARAM wParam,LPARAM lParam);

BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
         gl_hThisInstance = (HINSTANCE)hModule;
         hHook = SetWindowsHookExA(
            WH_KEYBOARD,
            KeyHit,
            //(HWND)gl_hThisInstance//not working
            0,//not working
            //(DWORD)gl_hThisInstance//not working
            //GetCurrentThreadId()//even not working with this
            0//not working
            );
        break;
    }
    return TRUE;
}

LRESULT CALLBACK KeyHit(int code,WPARAM wParam,LPARAM lParam)
{
    MessageBox(0,"PRESSED","PRESSED",0);
    return CallNextHookEx(hHook,code,wParam,lParam);
}

【问题讨论】:

  • 为什么要投到 HOOKPROC?如果编译器没有默默地做这个转换,那么 KeyHit 的签名是错误的。
  • 我删除了(HOOKPROC),它编译得很好,所以我认为这不是问题
  • 你为什么要投射gl_hThisInstance>它已经是正确的类型了...
  • 当你说“(DWORD)gl_hThisInstance//not working”是什么意思?
  • 还有first parameter to DllMain is HINSTANCE,所以也没有理由投那个。

标签: c++ winapi hook keyboard-hook


【解决方案1】:

我之前遇到过挂钩问题。不是真正的问题,但我这样做的方式不应该。 首先,您应该有 2 个从 DLL 导出的函数,SetHookRemoveHookSetHook 函数将从那里调用SetWindowsHookEx()。如果您尝试从线程内调用SetWindowsHookEx() 或DLL 的DLLMain,该函数不会返回错误,但永远不会调用回调函数。有时我才弄明白。

这里发布的是我捕捉WH_GETMESSAGE的工作代码,你可以从这里参考。

这是我从 DLL 导出的 SetHook() 函数。

bool __declspec(dllexport) __stdcall SetHook(DWORD myWnd)
{
    mySavedHook = SetWindowsHookEx(WH_GETMESSAGE,
        GetMsgProc,
        infoContainer.DllHModule,
        myWnd);

    int errorID = GetLastError();
    if (errorID != 0)
    {
        MessageBoxA(NULL, "Failed to implement hook", "Failed", 0);
        MessageBoxA(NULL, to_string(errorID).c_str(), "Error ID", 0);
        return false;
    }
    else
    {
        return true;
    }
}

infoContainer.DllHModule:DLL的实例,是DllMain()的第一个参数。 myWnd: 是我的线程 ID(不是进程 ID)- 从 GetWindowThreadProcessId(window_handle, NULL) 获取。要实现全局挂钩,请使用 0 作为myWnd

这是我的回调函数。

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        LPMSG msg = (LPMSG)lParam;
        if (msg->message == WM_CALLFUNCTION)
        {
            MessageBoxA(NULL, "Receive WM_CALLFUNTION", "Good news", 0);
        }

    }
    //Doesn't matter, just call this function and return it.
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

回调函数必须有CALLBACK 关键字才能工作。

在外部应用程序中,从 DLL 中调用 SetHook(),并使用线程 ID 作为其参数。

【讨论】:

  • 我不知道为什么有人在代码前后添加空格来编辑答案?
  • 嗨,我和 OP 有同样的问题。您建议我们导出SetHook()RemoveHook() 函数。我的问题是从哪里调用这些。我们可能不会从 DllMain() 或 DLL 中的线程中调用它们,因为不会调用钩子,正如你所说的(我也可以确认这一点)。我们可能不会从注入 DLL 的应用程序中调用它们,因为我们可能不会修改它的代码。另一个应用程序?那么它必须调用LoadLibrary()\GetProcAddress() 吗?或者还有什么办法?你能在这里解释一下吗?
  • @ConstantineGeorgiou 你找到从哪里调用这些函数了吗?
  • @Itay,我发现的最好的方法(虽然可能不是最好的,或者推荐的)是制作一个“启动器”.exe,它将调用 .dll 中的导出函数,这将设置钩子。并且钩子需要放置在共享数据段中,在代码中使用编译器/链接器指令,因为启动器和要注入的应用程序是两个独立的进程,因此会被实例化两次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-20
  • 2012-05-26
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多