Attaching to WndProc in WPF

WPF, like any other UI program, has an inner loop that continually runs in order to update the state of the application and render the UI.  One part of this loop is a call to the function WndProc, which is the function through which Windows communicates the messages your window is receiving (be it input or system notifications).

WPF hides this function from you (presumably to make things easier) and instead just fires events off for anything [it thinks] you’ll ever need.  Sometimes, however, it is useful to attach to this loop in order to address messages that don’t have a related WPF event, such as messages sent by other applications.

Here’s how you do it.

In your window’s SourceInitialized event, create an HwndSource object from your window’s handle. Use the AddHook method to attach an event handler to all of your window’s events using the supplied function.

private void Window_SourceInitialized(object sender, EventArgs e)
{
    IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
    HwndSource src = HwndSource.FromHwnd(windowHandle);
    src.AddHook(new HwndSourceHook(WndProc));
}

As its always good practice to define the methods you reference, be sure to define WndProc and, hopefully, do something useful with it. Its parameters describe the message by giving you its ID, as well as the parameters sent along with it. For some more on windows messages, check out my earlier post regarding emulating those messages. If your desired message has been captured and handled, be sure to set handled to true.

private IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    // address the messages you are receiving using msg, wParam, lParam
    if (msg == WM_LOOK_FOR_DROIDS)
    {
        if (wParam == DROIDS_IM_LOOKING_FOR)
        {
            CaptureDroids(lParam);
            handled = true;
        }
        else
        {
            AskToMoveAlong(lParam);
        }
    }
    return IntPtr.Zero;
}

Lastly, be sure to remove the hook when your window is closing.

private void Window_Closing(object sender, EventArgs e)
{
    IntPtr windowHandle = (new WindowInteropHelper(this)).Handle;
    HwndSource src = HwndSource.FromHwnd(windowHandle);
    src.RemoveHook(new HwndSourceHook(this.WndProc));
}

Easy as pie. If you’re feeling nostalgic and don’t want to use events, you can implement your entire application in the WndProc method (other than the rendering, which WPF also hides from you). I wouldn’t recommend it, though…