Low-Level Global Hooks in .NET 2.0
I recently wrote some code which needed to install a low-level global mouse hook. I promptly did a MSN search and came up with two good articles on the subject – a KB article and a MSDN mag article. So, I religiously copy-pasted the code from the KB article and it ran after giving a warning that AppDomain.GetCurrentThreadId()has been deprecated in .NET 2.0. But this was not a system hook, it was a local hook – as soon as my mouse pointer went out of my app’s bounds, it would keep mum.
So to get a system hook, I changed the WH_MOUSE to WH_MOUSE_LL. It simply refused to work with this – the hook wasn’t registering at all. Finally after hours of scratching around I found a blog by Stephen Toub where he uses global keyboard hook to write an add-in for Media Center. And it turns out that this call does the trick:
mouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL, mouseHookCallBack,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
Of course,
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
Apparently I wasn’t passing the HInstance earlier. Raymond Chen has a blog entry explaining why HInstance needs to be passed. But here’s my pickle – since the WH_MOUSE_LL is not injected but is executed in the hook’s registerer’s context itself, shouldn’t the thread ID be of more importance than the HInstance? Any takers?
Comments
Anonymous
March 12, 2006
I did exactly as you suggested, but the hook still only runs when i have my app in focus. IE - It's not global.Anonymous
March 12, 2006
to clarify that, it works when my mouse exits the sides of the form... but not if i take the focus away by clicking on another program.Anonymous
July 18, 2006
When the focus is on another app then the mouse messages you recieve would correspond to that app.Anonymous
May 16, 2007
According to the below URL: http://support.microsoft.com/kb/318804 Global hooks are not supported in the .NET Framework Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically. Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.Anonymous
October 04, 2007
Change the WH_MOUSE constant from 7 to 14. I guess it makes it globalAnonymous
December 03, 2011
Marshal.GetHINSTANCE(Reflection.Assembly.GetExecutingAssembly().GetModules()(0))