Steps to Import WPF controls into MFC Application

Step 1: Create an MFC Project

  • Open Visual studio
  • Go to Files -> New -> Project
  • Expand Other Project Types from Recent Templates from left panel and select Visual C++
  • Select MFC Application from the available projects list from Middle panel.
  • Give a Project Name, Select the Path and Click OK – Application Wizard opens
  • Click Next for the first screen and Select Dialog based radio button in the secomd screen (Application Type screen)
  • Click Finish – This creates an MFC Application with Header file, Resource files and Source files

Step 2: Change the default Configuration of the MFC Project to execute the managed code

  • Right click on the newly created MFC project and go to Properties
  • Select Configuration Properties from the left panel
  • Change the Common Language Runtime Support value to Common Language Runtime Support (/clr) from the dropdown in right panel
  • Click on Apply and OK buttons

Step 3: Add the required DLLs to the MFC Project to accept and recognize the WPF controls

  • Right Click on the newly created MFC project and Select Properties
  • Select Common Properties from the left panel
  • Click on Add New Reference button at the bottom – Add Reference window opens
  • Select .NET tab from the available tabs at the top.
  •  select the reference DLLs: PresentationCore, PresentationFramework, System, UIAutomationProvider, UIAutomationType and WindowsBase.
  • Click OK

Step 4: Add a new WPF project to the solution

  • Right Click on the solution
  • Select Add ->New Project
  • Select Visual C# from the left panel and select WPF Application from the available projects
  • Give a project name and clcik OK – New WPF project will be created in the same solution file.
  • App.xaml and MainWindow.xaml window files will be created by default in the newly created WPF application – Delete these two files from the project.
  • Right Click on the newly created WPF project and select Add -> New item
  • Select Page(WPF) from the available options from the middle panel
  • Give a name to the item and click on Add button – New page window will be added to the WPF project
  • Add the needed controls and styles to dispaly in the newly added page using Toolbox drag and drop or XAML.

Step 5: Change the WPF project type from windows application to Class Library

  • Right Click on the WPF project and go to Properties.
  • From the Output type dropdown select Class Library Close the Properties window and Build the WPF application.

Step 6: Add the WPF project reference to MFC Application

  • Right Click on the MFC Application and go to Properties
  • Select Common Properties from the left panel.
  • Click on Add New Reference button at the bottom – Add Refence window opens
  • Select Projects tab from the available tabs at the top.
  • Select the WPF Project which we have created in the solution earlier and click OK.

Step 7: Add the code level changes to the MFC Project (ProjectNameDlg.cpp file)

Addd the following Namespaces at the top before the Header file declaration:

   using namespace System;
   using namespace System::Windows;
   using namespace System::Windows::Controls;
   using namespace System::Windows::Media;
   using namespace System::Runtime;
   using namespace System::Runtime::InteropServices;
   using namespace System::Windows::Interop;

Add a Refenece class which has a static pointer the HwndSource object and WPF class ( after the Header declaration in the file )

Ex: ref class Globals {
   public:
   //HwndSource
   static System::Windows::Interop::HwndSource^ gHwndSource;
   //WPF class
   static WPFWindow::TestWPFPage^ gwcClock;
   };
Declare a HWND type to hold a refence to WPF window
   Ex:
   HWND hwndWPF;

Add a method to convert WPF control to HwndSource type

Ex:
   HWND GetHwnd(HWND parent, int x, int y, int width, int height)
   {
   System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew System::Windows::Interop::HwndSourceParameters ("MFCWPFApp");
     sourceParams->PositionX = x;
     sourceParams->PositionY = y;
   sourceParams->Height = height;
   sourceParams->Width = width;
   sourceParams->ParentWindow = System::IntPtr(parent);
   sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;
   Globals::gHwndSource = gcnew System::Windows::Interop::HwndSource(*sourceParams);
   //WPFWindow - Namespace of the WPF application
   //TestWPFPage - Class name of the WPF application
   Globals::gwcClock = gcnew WPFWindow::TestWPFPage();
   Globals::gHwndSource->RootVisual = Globals::gwcClock;
   return (HWND) Globals::gHwndSource->Handle.ToPointer();
     }

Find the Starting point of the MFC application (Like BOOL CMFCTestDlg::OnInitDialog() ) and from which call the newly added HWND method, and assign the returned HWND window type to the HWND object declared earlier.

Ex:  hwndWPF = GetHwnd(this->GetSafeHwnd(), 0, 0, 200, 200);

By Executing this, We will be able to access the controls we designed in the WPF project page in the MFC project.

Step 8: Other Challenges in the MFC Project (ProjectNameDlg.cpp file)

If we add a textbox control in the XAML file (WPF environment), the Textbox control will not accept any text except SPACE and BACKSPACE when imported into any non-WPF environment like MFC or Windows application etc.
To resolve this issue we have to add a handler in the non-WPF project file.
In the reference class which we defined earlier, add the following static method:

// Method to enable WPF textboxes to accept text
static System::IntPtr ChildHwndSourceHook(
  System::IntPtr hwnd,
  int msg,
  System::IntPtr wParam,
  System::IntPtr lParam,
  bool% handled)
{
  if (msg == WM_GETDLGCODE)
  {
  handled = true;
  return System::IntPtr(DLGC_WANTCHARS | DLGC_WANTTAB | DLGC_WANTARROWS | DLGC_WANTALLKEYS);
  }
  return System::IntPtr::Zero;
}
// End Method to enable WPF textboxes to accept tex

From the GetHwnd() method, Add the Hook to HwndSource object by calling the newly created static method

   // Call the HWND Hook with Method to enable WPF textboxes to accept text
   Globals::gHwndSource->AddHook(gcnew System::Windows::Interop::HwndSourceHook(
      &Globals::ChildHwndSourceHook));
   // End Call the HWND Hook with Method to enable WPF textboxes to accept text

This will set the WPF Textbox control to accept any text enetered by the user into it.

Tagged . Bookmark the permalink.

Leave a Reply