【问题标题】:SetWindowsHook stops working after some timeSetWindowsHookex 在一段时间后停止工作
【发布时间】:2010-11-30 17:01:19
【问题描述】:

我在 WM_MOUSE 上定义了一个全局挂钩,它可以在一段时间内完美运行。每次鼠标移动时,它都会向特定窗口发布一条消息。

随机时间后,钩子停止发送消息。如果我取消注册并注册钩子,它会再次工作。我想在 Windows 中发生的某些特定事情会导致钩子停止,但我找不到什么。

有什么想法吗?

编辑:当钩子不再处于活动状态时,我将调试器附加到其他进程,并且我观察到不再加载 dll。

什么可能导致挂钩 dll 卸载?

Edit2:我发现 MouseHookProc 中的崩溃,任何进程中的 dll 都会从它加载的每个进程中卸载钩子 dll。我无法在我的代码中找到导致崩溃的原因。可能是一些比赛条件或什么?这是钩子dll代码:

#include "stdafx.h"

// define a data segment
#pragma data_seg(".SHARED")
HWND  hwnd=0;
HHOOK hHook=0;
#pragma data_seg()

// tell the linker to share the segment
#pragma comment(linker, "/section:.SHARED,RWS")

#define WM_MOUSEHOOK            WM_USER+0x100

HINSTANCE hInstance=0;


// this allow to build a very small executable without any extra libraries
// (probably not the problem, the bug still occurs without this )
#ifndef _DEBUG
void *__cdecl operator new(unsigned int bytes)
{
    return HeapAlloc(GetProcessHeap(), 0, bytes);
}

void __cdecl operator delete(void *ptr)
{
    if(ptr) HeapFree(GetProcessHeap(), 0, ptr);
}

extern "C" int __cdecl __purecall(void)
{
    return 0;
}
#endif

BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{    
    hInstance=hModule;
    return TRUE;
}

LRESULT CALLBACK MouseHookProc(int nCode, WORD wParam, DWORD lParam)
{
    if(nCode==HC_ACTION && (wParam==WM_MOUSEMOVE || wParam==WM_NCMOUSEMOVE))
    {            
        MSLLHOOKSTRUCT *mhs=(MSLLHOOKSTRUCT*)lParam;        
        PostMessage(hwnd, WM_MOUSEHOOK, wParam, 0);
    }
    return CallNextHookEx(hHook,nCode,wParam,lParam);
}

extern "C" __declspec(dllexport) HHOOK InitializeWindowsHook(char *title)
{
    hwnd=FindWindow(0, title);
    if(hwnd)
        hHook=SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseHookProc, hInstance, 0);
    return hHook;
}

extern "C" __declspec(dllexport) BOOL DeinitializeWindowsHook()
{
    if(hHook) {
        BOOL b=UnhookWindowsHookEx(hHook);
        hHook=0;
        return b;
    }
    return FALSE;
}

【问题讨论】:

  • 你是否将消息传播到链中的其他钩子?
  • 我注意到虽然你有一个 WH_MOUSE 钩子,但你使用 MSLLHOOKSTRUCT 而不是 MOUSEHOOKSTRUCT 结构。
  • 其实你声明了*mhs但是你没有使用它。
  • 是的,我也试过 LL 钩子。我不想因为害怕删除对错误有意义的东西而过多地编辑代码。当然 mhs 是没用的,但我看不出它是如何导致崩溃或行为不端的。
  • 您使用的是 Windows 7 吗?我发现了这个线程:social.msdn.microsoft.com/Forums/en/…,它讨论了一个类似的问题。我自己也有同样的麻烦;如果 CPU 很忙,钩子(显然)超时并且永远不会再次被调用。

标签: c++ windows winapi mouse-hook


【解决方案1】:

您是否检查过钩子在不再被调用时是否仍然安装(即检查来自 BOOL UnhookWindowsHook 的返回值)?

可能安装了另一个不会保留您的钩子的钩子,而不是调用 CallNextHookEx()。

【讨论】:

  • 如您所见,我在每种情况下都会执行 CallNextHookEx。 UnhookWindowsHook 最有可能返回 ok,因为我有一些日志,但没有记录任何内容。
  • 你调用CallNextHookEx,但我的假设是在其他地方安装了一个不同的钩子,它不会调用CallNextHookEx。我不知道这是否是一个大型项目,您可能会在一个团队中进行协作。如果是,请扫描 SetWindowsHookEx 的所有代码。
【解决方案2】:

尝试改用WH_MOUSE_LL。

编辑:关于LowLevelMouseProc Function

钩子程序应该处理一个 在比数据更短的时间内发送消息 中指定的条目 LowLevelHooksTimeout 中的值 以下注册表项:

HKEY_CURRENT_USER\Control Panel\Desktop

该值以毫秒为单位。如果 钩子程序在期间不返回 这个间隔,系统会通过 下一个钩子的消息。

【讨论】:

  • 我试过了,但它经常触发,以至于它会减慢所有应用程序的速度,它会解决任何问题吗?
  • @Emmanuel Caradec,你不应该在钩子程序中做繁重的工作(有时间限制)。通知其他一些例程来完成这项工作(可能通过发布消息)并立即返回。
  • 实际上我唯一要做的就是向已经知道的 hwnd 发送消息。自从 wm_mouse 为我工作以来,我没有对 wh_mouse_ll 进行大量调查。 wh_mouse 有什么问题?
  • 我试图锁定 wm_mouse 很长时间,但它没有卸载 dll。它使 PC 运行缓慢,但这是意料之中的。
【解决方案3】:

我假设钩子函数是在 DLL 中实现的?也许某些东西减少了那个 DLL 的引用计数,所以 Windows 卸载它,这会停止你的钩子函数。

我建议你在你的DLL中做的第一件事是自己调用LoadLibrary,这样包含钩子函数的DLL的引用计数就会增加一个。千万不要打电话给FreeLibrary来测试这个理论。

【讨论】:

    【解决方案4】:

    顺便说一句,你应该 CloseHandle 你的钩子句柄。

    我能想到的唯一会导致崩溃的事情是如果您的挂钩手柄已被破坏。你能捕获异常吗?当发生的异常发生时,您是否尝试过 break on exception 来中断?如果您不知道发生了什么异常,您是否尝试过在代码周围添加 __try/__finally 块?

    【讨论】:

    • 今天我将添加一个 __try/__finally 块。我想有一个崩溃,因为这会导致完全相同的行为。我尝试取消引用一个空指针,这会导致每个加载的钩子 dll 的卸载。 Windows 可能会在钩子周围添加一个 __try,__finally 块,以便在它们表现不佳时卸载它们。
    • 我应该什么时候做一个closehandle?在 unhookwindowsex 之后?
    • 没错。对于您“创建”的每个句柄,您应该关闭它。我很确定 FindWindow 只会返回一个预先存在的句柄,所以它不需要关闭。我相信混乱是 COM 引入整个 addref/release 的原因:)
    【解决方案5】:

    您的钩子的基本数据是否在共享段中?这至少是接收通知消息的目标窗口的 HHOOK 和 HWND。

    【讨论】:

    • 是的,钩子可以完美地工作,有时在所有窗口和线程上,然后停止工作。
    【解决方案6】:

    聚会迟到了,但我也遇到了同样的问题,并通过创建一个新线程来执行我的任务并尽快从程序返回来解决。希望这对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多