Thread hook procedure is no longer called after pressing Tab several times. Why?

后端 未结 2 678
无人共我
无人共我 2021-01-06 08:37

I installed a thread-specific windows hook to monitor messages sent to WndProc. It worked at first. However, after I pressed Tab about 19 times to move focus around a form,

相关标签:
2条回答
  • 2021-01-06 09:01

    While testing your program I got the following error

    CallbackOnCollectedDelegate was detected
    Message: A callback was made on a garbage collected delegate of type 'Sandbox Form!Sandbox_Form.Program+HookProc::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

    I believe the problem is the delegate that is implicitly created to be passed in to SetWindowsHookEx for the callback is getting garbage collected. By explicitly creating a variable for the delegate and keeping it in scope I think it will make your problem go away, when I modified InstallHook to the following I could no longer re-create the error.

    private static HookProc hookProcDelegate;
    
    private static void InstallHook()
    {
        if (Program.hWndProcHook == IntPtr.Zero)
        {
            Console.WriteLine("Hooking...");
    
            hookProcDelegate = new HookProc(WndProcHookCallback);
    
            Program.hWndProcHook = SetWindowsHookEx(
                WH_CALLWNDPROC,
                hookProcDelegate,
                GetModuleHandle(null),
                GetCurrentThreadId());
    
            if (Program.hWndProcHook != IntPtr.Zero)
                Console.WriteLine("Hooked successfully.");
            else
                Console.WriteLine("Failed to hook.");
        }
    }
    
    0 讨论(0)
  • 2021-01-06 09:20

    What can cause Windows to unhook a low level (global) keyboard hook? covers this. This situation can occur if the hook procedure times out. The timeout value is specified at the HKEY_CURRENT_USER\Control Panel\Desktop key with the value LowLevelHooksTimeout (although this value was not present on my system).

    From MSDN (there is also some good info in Community Content at the bottom of this page):

    If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called.

    From Global hooks getting lost on windows

    On Windows 7 we have to make sure that the callback function of the hook can return in less than LowLevelHooksTimeout, which is 300 ms. And we allow for the application to be timed out 10 times when processing the hook callback message. If it times out an 11th time, Windows will unhook the application from the hook chain. This is a by design feature and it was added in Win7 RTM.

    That page also suggests using Raw Input instead.

    Edit: here is Code Project tutorial on using Raw Input in C#.

    0 讨论(0)
提交回复
热议问题