Windows Forms and MFC Integration using CWinFormDialog

 

One of the primary scenarios around integration of Windows Forms into an existing MFC application is around showing a Windows Form as a dialog, similar to CDialog class in MFC. Developer can create a MFC representation of an existing Windows Form control (System::Windows::Form::Control) created in either in C++ or C#. Then he can use this MFC control in existing MFC applications.

Let's explore this in an example. Assume you have a called HostedWinFormsControl and you want to integrate it with your existing MFC applications. Below are the steps to follow:

  • Add #include <afxwinforms.h> to stdafx.h.
  • Generate using Class wizard an MFC class that subclasses CDialog. You don't need resource template. Go ahead and delete it. Let's call this new class as CHostForWinForm.
  • Replace every appearance of CDialog in hostforwinform.h and hostforwinform.cpp with CWinFormsDialog<HostedWinFormsControl>.
  • To listen to events on your winform with MFC code, you need to add a delegate map, MAP_DELEGATE_MAP. This creates a proxy around your native class that is used to call methods of a native class when a managed event is fired.
  • Then you add OnButtonX() methods to your MFC class that are used as a handlers for Click events on winform side.
  • Last step is to organize data exchange, which is basically means to change DoDataExchange() method of the host MFC class as it is shown below.

 

And that's it. Now you can use this MFC class that hosts Winform as a regular MFC dialog. Here are the code snippets:

--------------------------------------------------------------------------------------------------------

HostForWinForm.h

--------------------------------------------------------------------------------------------------------

#pragma once

// CHostForWinForm dialog

class CHostForWinForm : public CWinFormsDialog<HostedWinForms::HostedWinFormsControl>

      // public CDialog

{

      DECLARE_DYNAMIC(CHostForWinForm)

public:

      CHostForWinForm(CWnd* pParent = NULL); // standard constructor

      virtual ~CHostForWinForm();

      virtual BOOL OnInitDialog();

// Dialog Data

// enum { IDD = IDD_HOSTFORWINFORM };

protected:

      virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

      DECLARE_MESSAGE_MAP()

     

/////////////////////////////////////////////

// CODE YOU ADD TO INTEGRATE WINFORM CONTROL

public:

      virtual void OnButton1( System::Object^ sender, System::EventArgs^ e );

      virtual void OnButton2( System::Object^ sender, System::EventArgs^ e );

      BEGIN_DELEGATE_MAP( CHostForWinForm )

            EVENT_DELEGATE_ENTRY( OnButton1, System::Object^, System::EventArgs^ );

            EVENT_DELEGATE_ENTRY( OnButton2, System::Object^, System::EventArgs^ );

      END_DELEGATE_MAP()

     

      CString m_sEditBoxOnWinForm;

};

--------------------------------------------------------------------------------------------------------

HostForWinForm.cpp

--------------------------------------------------------------------------------------------------------

#include "stdafx.h"

#include "HostForWinForm.h"

// CHostForWinForm dialog

IMPLEMENT_DYNAMIC(CHostForWinForm, CWinFormsDialog<HostedWinFormsControl>)

CHostForWinForm::CHostForWinForm(CWnd* pParent /*=NULL*/)

: CWinFormsDialog<HostedWinFormsControl>(CHostForWinForm::IDD, pParent)

{

}

CHostForWinForm::~CHostForWinForm()

{

}

void CHostForWinForm::DoDataExchange(CDataExchange* pDX)

{

      CDialog::DoDataExchange(pDX);

/////////////////////////////////////////////

// CODE YOU ADD TO INTEGRATE WINFORM CONTROL

      if (pDX->m_bSaveAndValidate)

            m_sEditBoxOnWinForm = CString( m_control->textBox1->Text);

      else {

            m_pControl->textBox1->Text = gcnew System::String(m_sEditBoxOnWinForm);

      }

}

BEGIN_MESSAGE_MAP(CHostForWinForm, CWinFormsDialog<HostedWinFormsControl>)

END_MESSAGE_MAP()

BOOL CHostForWinForm::OnInitDialog()

{

      CWinFormsDialog<HostedWinFormsControl>::OnInitDialog();

/////////////////////////////////////////////

// CODE YOU ADD TO INTEGRATE WINFORM CONTROL

      GetControl()->OkButton->Click += MAKE_DELEGATE( System::EventHandler, OnButton1);

      GetControl()->CancelButton->Click += MAKE_DELEGATE( System::EventHandler, OnButton2);

      return TRUE;

}

/////////////////////////////////////////////

// CODE YOU ADD TO INTEGRATE WINFORM CONTROL

void CHostForWinForm::OnButton1( System::Object^ , System::EventArgs^ )

{

   CDialog::OnOK(); // This will close the dialog and DoModal will return.

}

/////////////////////////////////////////////

// CODE YOU ADD TO INTEGRATE WINFORM CONTROL

void CHostForWinForm::OnButton2( System::Object^ , System::EventArgs^ )

{

   CDialog::OnCancel(); // This will close the dialog and DoModal will return.

}

Note this code snippet was fully tested in the final release of VS2005. I have not tested it since because it was not the area of my main focus. Lately I was posting on web services, guidance to developers around developing windows applications and best practices in program management and project management. You may check out other posts on MFC here. Here are some that you may find interesting:

  1. Complete Example of MFC and Windows Forms Integration
  2. Integrating Windows Vista Aero Wizards into existing MFC Applications.
  3. Resolving common error around resolving private member during porting MFC applications.

 

If you have questions and need more help in integrating Windows Forms in your MFC applications, please ask questions on Visual C++ MFC forum.