Developer Day 2010
Resource Management in Interop Scenarios

MFC and WPF Interop

Nowadays still many MFC applications exist. And maybe there’s no reason to rewrite the application as MFC gets big improvements with Visual Studio 2010. With that in mind it would be great to integrate WPF controls within MFC. Of course that’s possible!

Interoperability between MFC and WPF is based on two major features:

  • Managed and native code interop
  • Window handles to WPF elements

Using managed and native code in a mixed way can be done with C++/CLI. C++/CLI allows using managed code from native classes and the other way around. Instead of extending the C++ language with keywords starting with __ (which was done with Managed C++), C++/CLI is a syntax that extends C++ with managed keywords such as ref to define a managed ref type, value to define a managed value type, and gcnew to allocate an object on the managed heap. The C++/CLI syntax was already discussed in some older blog entries that are referenced below, and some new ones will follow.

So the first step on MFC and WPF interop are

  • Create a WPF library, e.g. with a user control
  • Create a MFC application
  • Add Common Language Runtime support to the MFC application (Configuration Properties -> General)
  • Reference the necessary assemblies (Common Properties –> Framework and References)
    • At least these should be: System, PresentationCore, PresentationFramework, WindowsBase, and of course the assembly holding the user control.

Interoperability with WPF is done by creating and using Window handles to the WPF control.

To do this the .NET class HwndSource from the System.Windows.Interop namespace represents a WPF control in a Win32 window. This class derives from the base class PresentationSource that is an abstract class that can be used to map different technologies to WPF. HwndSource is the concrete class to offer Window handles.

The base class PresentationSource provides several static methods and properties to get and enumerate presentation sources. Presentation sources are added and removed by a derived class that invokes the base class members AddSource and RemoveSource.

HwndSource implements a Windows handle to wrap a Visual object that is a base class of WPF elements. Settings that can be assigned to the HwndSource are the position, height and width, the parent window, and window class styles.

The following code snippet shows the method GetUserControl1Hwnd that is implemented as a private member of the MFC dialog class. In this method a WPF control is instantiated, and this is assigned to the RootVisual property of the HwndSource object. The configuration of the new window is defined by setting the position, height, and width, the parent window, and the window class style. HwndSource can be configured by passing HwndSourceParameters to the constructor (as it is done in this code snippet), or passing separate values to a constructor overload. If the Window handle is needed, the HwndSource class defines the Handle property that returns an IntPtr. With this structure the ToPointer method returns a void*.

HWND CMFCDialogAppDlg::GetUserControl1Hwnd(HWND parent, int x, int y, int width, int height)
{
HwndSourceParameters^ sourceParams = gcnew HwndSourceParameters("MFCWPFApp");
sourceParams->PositionX = x;
sourceParams->PositionY = y;
sourceParams->Height = height;
sourceParams->Width = width;
sourceParams->ParentWindow = IntPtr(parent);
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;
m_hwndSource = gcnew HwndSource(*sourceParams);

m_wpfUC = gcnew UserControl1();

m_hwndSource->RootVisual = m_wpfUC;

return (HWND) m_hwndSource->Handle.ToPointer();
}

For keeping a reference to a managed object in a unmanaged class (for example a reference to the WPF user control within the MFC dialog), it must be taken care of that the garbage collector does not release the managed object because no managed reference exists to it. Keeping the managed object can be done with the GCHandle structure that is a .NET value type from the namespace System.Runtime.InteropServices. GCHandle defines the static method Alloc that allocates and returns a GCHandle to a .NET objects. The instance method Free releases the reference to the object. The method ToIntPtr returns a native pointer that can be used by API methods.

Instead of using GCHandle directly, a gcroot object can be declared as a member of the class. gcroot is a native type defined within <vcclr.h> and wraps GCHandle for easy use. The constructor of this class allocates the GCHandle, and the destructor releases it.

gcroot here is used to define members to the WPF user control in the native dialog class.

gcroot<HwndSource^> m_hwndSource;
gcroot<UserControl1^> m_wpfUC;

Finally, the method GetUserControl1Hwnd where the WPF user control is instantiated is invoked on creation of the dialog. The first argument defines the parent window which is the window of the dialog itself. The method GetSafeHwnd of the base class CWnd returns the member m_hWnd, the window handle that is attached to the dialog or NULL.

int CMFCDialogAppDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;



m_hwndWPF = GetUserControl1Hwnd(this->GetSafeHwnd(), 20, 20, 200, 150);

return 0;
}

Now the WPF user control is created and assigned as a child window to the dialog. The members of the WPF control can be easily invoked by using the reference to the managed object.
 

Older blog entries about C++/CLI:

More information on C++/CLI and interop between native and managed code in my Take off to C++/CLI workshop.

Christian

Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

Naveen

I have followed the way you have suggested in hosting a wpf user control in an MFC modal dialog. I have used the HWndSource to wrap the wpf control and embedded that as a child in MFC dialog application.

Everytime I have closed and open the MFC dialog, I see a continuous memory growth, the previous allocation does not seems to be fired.

In the wpf user control's dispose method, I have set the references of all the objects that I have used to null. In the destructor of the dialog, I have called the delete on HWndSource and Wpf User Control, so that the dispose is getting called, but I still see memory not being released

Christian

Naveen, I've added information in my next blog entry: http://weblogs.thinktecture.com/cnagel/2010/07/resource-management-in-interop-scenarios.html. You did all this? How big is the additional allocation every time the dialog is opened? Maybe it's just memory from the managed heap until the GC cleans up.

charu

i have created one wpf user control having some textboxes.
this user control i hosted in MFC application using your approach.while running this application i am not able to edit values in the textboxes. can u help me.

קניית דומיין

Your work is inventive and valuable. Thank you for this fascinating post! Attractive section of content. Your blog is great for anyone who wants to understand this subject more. This is great stuff.

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Your Information

(Name and email address are required. Email address will not be displayed with the comment.)