0

I need to install a WH_KEYBOARD_LL hook in my WPF application, that by itself is not a big problem. However I need to install it in a thread other than my main application thread because otherwise the cursor will freeze when the UI thread is busy. I have read this article and this SO question, but it is not quite working yet. A comment in the question suggest me to start an Application in the thread that I create the hook, but then I get and exception saying I can't start 2 applications in the same AppDomain. Are there any solutions to this or is there another, easier way to install the hook in another thread?

Community
  • 1
  • 1
user1151923
  • 1,853
  • 6
  • 28
  • 44
  • IMO absolutely no need for a second application. What's for? From [MSDN](http://msdn.microsoft.com/en-us/library/windows/desktop/ms644985(v=vs.85).aspx): _"If the application must use low level hooks, it should run the hooks on a dedicated thread that passes the work off to a worker thread and then immediately returns. In most cases where the application needs to use low level hooks, it should monitor [raw input](http://msdn.microsoft.com/en-us/library/ms645536(VS.85).aspx) instead."_. – Adriano Repetti Aug 26 '14 at 10:06
  • @AdrianoRepetti Well the "dedicated" thread needs to stay alive somehow and not exit once it has installed the hook. How could I complete that? Also what about the line "the thread that installed the hook must have a message loop. "? – user1151923 Aug 26 '14 at 10:51
  • Thread will stay alive _because_ of message loop (as _main_ thread does). Anyway what I mean is: what's the reason you need such hook? Because _maybe_ hooks aren't best solution here (BTW if main thread is busy enough to make UI unresponsive then maybe no one will care about "frozen" text cursor (assuming you're not using a global hook). – Adriano Repetti Aug 26 '14 at 11:25

1 Answers1

1

You can create a new thread with a WPF dispatcher using this code:

public class DispatcherBuilder : IBuilder<Dispatcher>
{
    public Dispatcher Build()
    {
        Dispatcher dispatcher = null;
        var manualResetEvent = new ManualResetEvent(false);
        var thread = new Thread(() =>
            {
                dispatcher = Dispatcher.CurrentDispatcher;
                var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
                SynchronizationContext.SetSynchronizationContext(synchronizationContext);

                manualResetEvent.Set();
                Dispatcher.Run();
            });
        thread.Start();
        manualResetEvent.WaitOne();
        manualResetEvent.Dispose();
        return dispatcher;
    }
}

The Build method creates a new thread with a WPF Dispatcher and correct synchronization context on it. This thread runs until you shut down the dispatcher. You could then use e.g. Dispatcher.BeginInvoke to create your hook.

feO2x
  • 5,358
  • 2
  • 37
  • 46
  • Thank you for your answer, I however found it easier (and shorter) to just call System.Windows.Forms.Application.Run(); instead after setting the hook in the background thread. – user1151923 Aug 26 '14 at 11:49
  • That's ok but you'll carry all the Win Forms overhead with you. – feO2x Aug 26 '14 at 11:51