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 (6)

  1. DeadRinga says:

    I did exactly as you suggested, but the hook still only runs when i have my app in focus. IE – It’s not global.

  2. DeadRinga says:

    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.

  3. srivatsn says:

    When the focus is on another app then the mouse messages you recieve would correspond to that app.

  4. Satya says:

    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.

  5. yemixnuga says:

    Change the WH_MOUSE constant from 7 to 14.

    I guess it makes it global

  6. hi says:

    Marshal.GetHINSTANCE(Reflection.Assembly.GetExecutingAssembly().GetModules()(0))