locked
Shell Hooks in .NET RRS feed

  • Question

  • I'm trying to play around with using a Windows hook to tell when different application windows are openned or activated.  It's not working right; I'm not sure what's wrong.  When I first run my application, there is at most one call to ShellProc.

    Here's what's really confusing me: if I change the argument to SetWindowsHookEx from WH_SHELL to WH_KEYBOARD_LL, then I get every single keyboard event that happens even in other applications.  This is correct behavior.  But when using WH_SHELL I never get more than one event, and sometimes not even that.  Does anyone have any suggestions?

     

    Win32.HookProc shellProcDelegate;

    IntPtr windowsHook;

    public ShellHook()

    {

    shellProcDelegate = ShellProc;

    using (Process p = System.Diagnostics.Process.GetCurrentProcess())

    {

    ProcessModuleCollection modules = p.Modules;

    ProcessModule m = null;

    Assembly *** = Assembly.GetAssembly(typeof(ShellHook));

    string filename = System.IO.Path.GetFileName(***.Location);

    for (int i = 0; i < modules.Count; i++)

    {

    if (modulesIdea.ModuleName == filename)

    {

    m = modulesIdea;

    break;

    }

    }

    IntPtr moduleHandle = Win32.GetModuleHandle(m.ModuleName);

    windowsHook = Win32.SetWindowsHookEx(Win32.HookType.WH_SHELL, shellProcDelegate, moduleHandle, 0);

    int error = Marshal.GetLastWin32Error();

    }

    }

    int ShellProc(int code, IntPtr wParam, IntPtr lParam)

    {

    //UpdateApplications();

    System.Media.SystemSounds.Asterisk.Play();

    Debug.Print("{0} {1} {2}", code, wParam, lParam);

    return Win32.CallNextHookEx(windowsHook, code, wParam, lParam);

    }

    Thursday, January 4, 2007 12:32 AM

Answers

  • Global hooks set by SetWindowsHookEx() require Windows to inject the DLL containing the hook procedure into the address space of other running processes.  You can't inject the CLR, it cannot be initialized properly.

    I guess you could inject an unmanaged DLL but it would need some kind of out-of-process communication technique to pass the data.  Discounting the *very* nasty synchronization problems, you'll bring system performance to a screeching halt.
    Friday, January 5, 2007 2:26 PM

All replies

  • You simply can't create global hooks in managed code (with the exception of WH_KEYBOARD_LL and WH_MOUSE_LL).
    Thursday, January 4, 2007 9:33 AM
  • Why not?  Is there some documentation I can read about that?  That seems confusing that some would work but others wouldn't.  Do you think an alternative approach would be to create an unmanaged dll in C which has the hook in it, and have the managed code pass it a callback function?
    Friday, January 5, 2007 1:18 AM
  • Global hooks set by SetWindowsHookEx() require Windows to inject the DLL containing the hook procedure into the address space of other running processes.  You can't inject the CLR, it cannot be initialized properly.

    I guess you could inject an unmanaged DLL but it would need some kind of out-of-process communication technique to pass the data.  Discounting the *very* nasty synchronization problems, you'll bring system performance to a screeching halt.
    Friday, January 5, 2007 2:26 PM
  • so, is there any other way to be notified when the active application changes, without constantly polling?
    Friday, January 5, 2007 8:49 PM
  • Let's tackle this from the other end: why do you need to know?
    Friday, January 5, 2007 9:57 PM
  • I would also like to know if there is an answer to this question. I am currently in the process of planning to write a shell for Windows Vista. I want it to be a WPF application written in C# so i can take advantage of all of the advanced graphics. As far as the practicality of a WPF shell..... this is more of a fun experiment to see if it can be done.

     

    If I do create a wpf app in C# to use as a shell.... how could I handle any window management functions (taskbar style functionality) if global hooking is not possible from managed code?

     

    I suppose I could create a kind of lightweight ghost process in C++ which does the hooking and then communicates with my WPF app via window messages or something.

     

    Any advice you could give me would be great!

    Friday, February 1, 2008 7:11 AM
  • Funny, LCARS! I had the same idea as you (to create a WPF shell). Propably not in the LCARS style, but anyway Smile

     

    Did you find out something on that issue? I'm also interested in replacing the notification area (system tray), means hooking in the shell events to do my own stuff there. Any news?

     

    Keep smiling!

     

    Tuesday, April 1, 2008 2:57 PM
  • I have examined it a bit more and decided that the best option would be to make a helper process in unmanaged code (like C++) to intercept the global hooks. The process would go something like this:

     

    1.) The WPF Application main .exe is launched.

    2.) The WPF Application executes the unmanaged helper process.

    3.) The unmanaged helper process would store the hWnd of the WPF Application's main window into a global variable.

    4.) The unmanaged helper process would then register a WH_SHELL hook using the SetWindowsHookEx API.

    5.) The unmanaged helper process then sits and waits for any window message events.

    (Once a window message event is received)

    6.) The unmanaged helper process will send a message using WM_COPYDATA to the WPF Application's main window. I would probably pass a struct containing two variables: one that identifies the type of window event (say.. a window was minimized) and another that contains the hWnd of the specific window the event is for.

    7.) The WPF Application's main window receives the message and takes whatever action is needed (like fancy animations Stick out tongue).

     

    In the code for the WPF Application's main window, I would create a wndproc function so I can implement code to monitor for the WM_COPYDATA message. I would also add some code to do error handling like monitor the helper process and re-open it in case it is closed for some reason.

     

    As far as emulating the notification area, I have spent a few years researching that and managed to scrounge up a few (very few) peices of information. The most informative is a webpage I found which contains some research done by an individual at Kent university. They did some experimentation to try and uncover the inner workings of the notification area. I don't know if the page is still on the web but I did save a copy of it to my hdd as an xps file for my reference. If you'd like, I would be happy to send it to you.

     

    If you find any additional information on any of these topics, or any shell topics for that matter, I would love to hear about it!

    Tuesday, April 1, 2008 9:15 PM
  • Okay. Ten years have passed since the last time this publication was commented. I doubt that LCARSNxG can even read this comment, but I have to try.

    Did someone found something of interest? I'm doing the same as LCARSNxG and Ronald_81, i'm building an Custom Shell using C# and a WinForms/WPF Mixing, and need to know if there is any method to get the system tray icons, of at least tell me something about your plains, that would really interest me!

    Thursday, December 13, 2018 5:10 AM