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,
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.");
}
}
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#.