dev – one that develops

October 30, 2007

WPF-Win32 interop with HwndSource

Filed under: Interop — Tags: — rubio67 @ 10:12 am

I was given a task to design a new GUI using WPF, and then interface that with some legacy Win32 code. The challenge of course was the interop between the native side and the managed side. I looked up some sample code from MSDN and a couple of books, and thought I was well on my way. The idea was to host WPF controls in an MFC CDialog. Switching the MFC project into managed code was not an option, so I decided to create a mixed-mode MFC Extension DLL. This would allow me to wrap the WPF controls inside a CWnd, which I would then be able to use in a native CDialog. WPF interop provides a HwndSource class for hosting WPF content in a HWND window. I actually learned this technique from Nishant Sivakumar’s book C++/CLI in Action.



Everything worked beautifully until I tried to write text into a WPF TextBox. Nothing happened. I was able to delete characters by pressing Del or Backspace. HwndSource has its own window procedure and is supposed to handle message dispatching so I was baffled. Little testing showed that the TextBox was firing KeyDown events but not TextInput events. KeyDown is equivalent to WM_KEYDOWN and TextInput is equivalent to WM_CHAR. Somewhere along the way the WM_CHAR messages were lost. Turns out the standard dialog message loop calls IsDialogMessage, which “eats up” WM_CHAR messages. Had I been using a modeless dialog or a non-dialog window, everything would have worked. MS dev support suspected this might be a flaw in the WPF interop and might be fixed later.

And now the workaround. HwndSource allows you to add hooks to the event handler. The following shows an event hook that will ensure WM_CHAR messages are dispatched to the WPF side.

IntPtr ChildHwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool% handled)
{
   if (msg == WM_GETDLGCODE)
   {
      handled = true;

      return IntPtr(DLGC_WANTCHARS);
   }

   return IntPtr(0);
}

...

HwndSource^ source = gcnew HwndSource(sourceParams);
source->AddHook(gcnew HwndSourceHook(ChildHwndSourceHook));

Thanks to Chango for the workaround. You can download sample code here.

Update: – 1/11/08 Added sample project

About these ads

10 Comments »

  1. Thanks for the hint, it was really helpful.
    Furthermore I needed to use DLGC_WANTALLKEYS to allow tabbing inside WPF and to allow left-right arrows inside WPF TextBox controls, as well.

    Comment by akur — January 22, 2008 @ 8:25 am

  2. Does anyone have any source code that uses use the editbox in the WPF dll in the application directly without having to use an Extension DLL as a proxy.

    If you do you can email me the source code at steve_44@inbox.com

    Comment by steve fred — October 13, 2008 @ 9:34 pm

  3. Hi Steve,

    The premise in the app described in the blog post is that the application has to remain native. If you want eliminate the extension DLL (MixedMfcExt.dll), then your application, as far as I know, has to be mixed mode. That actually makes it much easier. I don’t have sample code for you (sorry), but if you look at the implementation of MixedMfcExt.dll you should get a pretty clear idea of how its done.

    Comment by rubio67 — October 14, 2008 @ 6:39 am

  4. I am looking for some source that shows how to load and unload a wpf dll into an mfc application during run time. Anyone know where I can find a link . If so could you send me the link at steve_44@inbox.com

    Comment by sunwatersnow — December 26, 2008 @ 3:53 pm

  5. Hi everybody,
    very interesting post!
    I’m trying to develop an User Interface for a Win32 app with a WPF dll.
    Which do you think is the best way in order to do that?

    Comment by Carmelo — December 27, 2008 @ 1:36 pm

    • Hi Carmelo,

      That’s a pretty broad question. It would be nice to just use P/Invoke, but that would only work for a trivial application. WPF is all about data binding which means taht you have to have managed object to bind to. That means that you will have to write managed wrappers for your native business objects. That, unfortunately, is not an easy task. Ultimately it comes down to estimating how much work would go into writing the wrappers as opposed rewriting your business layer in C# (or VB.NET). Take a look at Marcus Heege’s and Nishant Sivakumar’s books on C++/CLI. Nathan Adam talks a little bit about native interop on his book about WPF.

      Happy coding.

      Comment by rubio67 — October 6, 2009 @ 7:34 am

  6. Carmelo,

    I haven’t been very active with this blog, but since I had a draft of a simple C++/CLI wrapper class, I posted it. See the latest entry in my blog. Writing wrappers is kind of a bore, and can get tricky sometimes if your native data structures are complicated. Also remember that crossing the native-managed boundary can be costly in terms of performance. Some of the wrappers I wrote actually contained caching to alleviate the performance issues.

    Comment by rubio67 — October 6, 2009 @ 7:59 am

  7. What a nice article you have here. It seems you have gathered some great experiences around the whole c++/cli/c# wrappers subject.

    I am currently given the task to explore the possibility to use a WPF GUI for a native MFC app.Your sample code works beautifully, and it is the perfect thing for my case (can’t set the /clr switch on the native application (but most examples do)). But one question remains. Are you able to debug the managed code from the native code ? I am not able to break anywhere in the managed code with your sample.

    Comment by Louis — July 15, 2011 @ 3:43 pm

    • @Louis
      It’s been a while since I used C++/CLI and have since moved to all-managed world. From what I can remember, when I wanted to debug the managed side I would define the native EXE as the start application in the managed DLL project, then start debugging on the DLL project. Just open the properties page of your WpfGUI project, open the Debug tab and in Start Action select Start External Program. Then set the external program to point to your native EXE (NativeCaller.exe in my sample solution). Then start debugging the WPF DLL. You won’t be able to step into managed code from native code, but you will at least hit your breakpoints. My info on this is a few years old so it might be worth posting a question about this on MSDN forums or stackoverflow.

      Comment by rubio67 — July 16, 2011 @ 9:03 am

  8. what about shortcuts in the native application ? it seems they’re handled BEFORE WPF. so, this is not working.
    I’m looking for a way to disable them when WPF has focus…

    Comment by droopy6 — September 16, 2012 @ 7:44 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: