I recently had to host a WPF control in an MFC application. These are my notes on how to do it, along with some extras near the end.
MSDN has an article, WPF and Win32 Interoperation Overview, that describes how to host a WPF control in a Win32 application. The instructions on Win32 hosting WPF are quite good, and there’s a code example in Walkthrough: Hosting WPF Content in a Win32 Application.
MFC is essentially a wrapper for part of the Win32 API. As a result, the procedure for hosting a WPF control in an MFC app is very similar to the procedure for hosting a WPF control in a pure Win32 app. The following is a mapping of the steps listed in the WPF-Win32 interop article to the steps I took in MFC.
1. Create WPF content.
2. Implement a Win32 application with C++/CLI.
Implement an MFC app. (I created a new one as a test app, dialog-based for simplicity.) Then, set the MFC app to compile with managed code (with /clr).
- Right click on the MFC project in the Solution Explorer.
- Configuration Properties → General
- Set Common Language Runtime support option to Common Language Runtime Support
/clr.
With this option set, the MFC app now has access to the .NET Framework Library via C++/CLI syntax. In addition, add references in the MFC app (right click on the MFC app in the Solution Explorer, References) to the following four .NET assemblies for WPF support:
- WindowsBase
- PresentationCore
- PresentationFramework
- System
3. Set threading model to STA (single threaded apartment).
In project properties, go to Configuration Properties → Linker → Advanced → CLR Thread Attribute Property to STA threading attribute (/CLRTHREADATTRIBUTE:STA).
4. Handle the WM_CREATE notification in your window.
Using the IDE, add a handler for the WM_CREATE message. The IDE creates function OnCreate().
5. Within the handler
- Create a new
HwndSourceobject with the parent windowHWNDas its parent parameter. - Create an instance of your WPF content.
- Assign a reference to the WPF content object to the HwndSource object RootVisual property.
- The
HwndSourceobject’sHandleproperty contains the window handle (HWND). To get anHWNDthat you can use in the unmanaged part of your application, castHandle.ToPointer()to anHWND.
6. Implement a managed class that contains a static field that holds a reference to your WPF content object.
- Allows you to get a reference to the WPF content object from your Win32 code.
- Prevents your
HwndSourcefrom being inadvertently garbage collected.
7. Receive notifications from the WPF content object by attaching a handler to one or more of the WPF content object events.
There is a good example, with code, from Microsoft Support where they attach an MFC-style handler to the WPF control’s cut and paste events: Hosting a WPF Control in MFC and Enable Cut-and-Paste. I used this sample code as a model to implement steps 5, 6, and 7.
8. Communicate with the WPF content object by using the reference you stored in the static field to set properties, call methods, etc.
For the steps I took above, I used Visual Studio 2008 SP1, .NET Framework 3.5, and MFC 9.0. I also used a slide deck on WPF Interop from Jaime Rodriguez, who was one of the presenter/instructors in the WPF LOB Training Tour I attended a few months back. The following are some quick bullet notes I took in his “Tips and Tricks” session on WPF Interop. (These are my notes I took while Jaime was presenting, so it is a mix of what he presented and what I was thinking. They are not a direct transcription of what Jaime presented.)
- A Win32 app hosting a WPF control needs to be compiled with
/clr. - No nested hooks: can’t do something like host WPF in WinForms in Win32 or host WPF in Win32 in WPF. No guarantees.
- Issue: WinForms control dialogs always come up on top. Workaround: WPF popup (window) that shows over the WinForms control.
- Example of Win32 hosted in WPF: Microsoft Expression Design. The canvas is Win32, everything else is WPF.
- Obviously, hosting Win32 or WinForms in WPF allows for reuse of complex code that does not need to be rewritten.
- Another example of Win32 hosted in WPF: Blockbuster Video app. WPF app contains Windows Media Player, which is Win32. Rationale: Windows Media Player performance is currently better than WPF video player because Windows Media Player is more advanced—team has been developing it longer, it uses the hardware better.
- Although WinForms and WPF interoperate (via a mechanism like
WinFormsHostin WPF), cannot directly convert WinForms designs to WPF designs because WinForms designs serialize to code, while WPF designs serialize to XAML.
Most of the examples and discussion out there addresses hosting Win32 components in WPF app shells because new apps from scratch are generally written in WPF, with reuse of Win32 components (likely drawing components written using GDI that does not need to be rewritten immediately to support DirectX). Hosting WPF in Win32/MFC is less common, but does provide a migration path toward WPF when has an existing application but wants to make use of some of the new GUI technology. One thing to take into consideration in both cases is planning the layout (and considering the “airspace”). Designate regions of the app (like a document/drawing canvas or a major control panel) to be Win32 while the remainder of the app is in WPF, rather than mixing and matching Win32 and WPF ad hoc, a Win32 button here, a WPF button there.
References
Microsoft. (n.d.). WPF and Win32 Interoperation Overview. Retrieved on July 7, 2009, from http://msdn.microsoft.com/en-us/library/ms742522.aspx#.
Microsoft. (n.d.). Walkthrough: Hosting Windows Presentation Foundation Content in a Win32 Application. Retrieved on July 7, 2009, from http://msdn.microsoft.com/en-us/library/ms744829.aspx.
Microsoft. (2008). Hosting a WPF Control in MFC and Enable Cut-and-Paste. Retrieved on July 7, 2009, from http://support.microsoft.com/kb/959082.
Miranda, T. (2009). WindowsClient.NET: Video Training – Host a WPF Control in a Win32 Application. Retrieved on July 7, 2009, from http://windowsclient.net/learn/video.aspx?v=13252.
Rodriguez, J. (2009). Jaime Rodriguez on .NET Client: Thanks Chicago. Here is the Content. Retrieved on July 9, 2009, from http://blogs.msdn.com/jaimer/archive/2009/06/16/thanks-chicago-here-is-the-content.aspx.
Sells, C., & Griffiths, I. (2007). Programming WPF: Building Windows UI with Windows Presentation Foundation (2nd ed.). Sebastopol, CA: O’Reilly Media.