I’m trying to communicate with a native library that uses an HWND to pass messages back to the caller as follows:
private void Example()
{
using (
var hwnd = new HwndSource(
new HwndSourceParameters("I sense a disturbance in the force...") {HwndSourceHook = WndProc}
)
)
{
//send hwnd.handle to native library
while (true) { }
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool ishandled)
{
ishandled = false;
Console.WriteLine("Intercepted message: 0x{0:X}", msg);
return IntPtr.Zero;
}
Even when the call the the native library is omitted, I only ever receive the following messages (in order):
- 0x0001:
WM_CREATE - 0x0018:
WM_SHOWWINDOW - 0x0046:
WM_WINDOWPOSCHANGING - 0x0046:
WM_WINDOWPOSCHANGING - 0x001C:
WM_ACTIVATEAPP - 0x0086:
WM_NCACTIVATE - 0x007F:
WM_GETICON - 0x007F:
WM_GETICON - 0x007F:
WM_GETICON - 0x0006:
WM_ACTIVATE - 0x0281:
WM_IME_SETCONTEXT - 0x0282:
WM_IME_NOTIFY - 0x0007:
WM_SETFOCUS - 0x0085:
WM_NCPAINT - 0x0014:
WM_ERASEBKGND - 0x0047:
WM_WINDOWPOSCHANGED - 0x0083:
WM_NCCALCSIZE - 0x0085:
WM_NCPAINT - 0x0014:
WM_ERASEBKGND - 0x0005:
WM_SIZE - 0x0003:
WM_MOVE - 0x000D:
WM_GETTEXT
After this I can drag the window corresponding to the HwndSource around but am unable to resize or close it. Furthermore the operating system claims that this window is not responding.
Why does this window stop responding and how can I continue to intercept messages?
As both @HansPassant and @HassanBoutougha pointed out the issue is with the following segment of code:
while (true) { }While this may look like it’s innocently keeping the application alive what it’s really doing is preventing the dispatcher from processing messages. The messages that I was seeing was because they were being called directly from within the thread executing
Example()by theHwndSourceconstructor. After construction the application enters the loop and runs around in circles. Unfortunately this is the thread that’s suppose to be processing the messages!Essentially the correct solution here was to tell the dispatcher to put the current call stack on the back burner and process events until we tell it to stop.
Essentially the call to
Dispatcher.PushFramethis tells the dispatcher to suspend execution and continue listening to messages. At some point in the future if you decide that you want to resume execution where you left of just do the following:And that’s it! The call to
Dispatcher.PushFramewill now return and resume executionKent Boggart has a great example here: http://kentb.blogspot.ca/2008/04/dispatcher-frames.htmlUnfortunately Kent’s blog is no longer available however a snapshot of the page from Google’s cache may be found here.