In an e-mail to my first article "Hosting a MFC MDI application from within WinForms and WPF applications" I received a question - "Is it possible to build a container of MFC applications using the described technology?" This task has caused a little change of architecture to make components more flexible. Such work always brings pleasure, and it was the main motivation for this article. On the other hand, the result looks like an OLE container, but I have done this without creating COM objects!
I used two applications as samples: UmlEditor (MDI) and DialogEditor (SDI) by Johan Rosengren. We can simply embed both these applications in WinForms or the WPF framework, using
MfcAdapter. For simplicity, I used
RichTextBox based demo editors "
FormsDemo" (WinFroms) and "
WPFDemo" (WPF) as such kind of a container:
The main change is to divide
MfcAdapter and MFC application in separate components. In this case, we will have an
MfcAdapter that is fully independent from an actual MFC application:
The low level .NET component in the described architecture is a Mixed (managed/unmanaged) DLL with an MFC application and the managed class
ModuleState is a managed pointer to unmanaged
AFX_MODULE_STATE of the MFC application. With
MfcAdapter or other C++/CLI component can load
AFX_MODULE_STATE from necessary Mixed DLL. After this
MfcAdapter can switch to this
AFX_MODULE_STATE and use the unmanaged API of the hosted MFC application. Additionally, the Mixed MFC DLL provides managed equivalents to
CommandIDs which can be processed in the MFC application.
To host MFC application in WinForms/WPF framework, as described in my first article, we should:
- Keep an invisible
CMainFrame and a created
CView. I have updated the application initialization and set
bMakeVisible parameter to "
false" in the overridden document template to implement this. The good news is we don't need to override
CDocManager and to change document like in previous version of
- Keep the modal properties of the hosted dialogs. Create the MFC MainFrame window as child of Framework MainForm window. Use the
CNotifyHook in the MFC MainFrame for supporting modal MFC dialogs in external framework.
- Auto-layout support. We have to implement some methods from
CLayoutView class in our hosted view:
The detailed description of necessary MFC code changes and Project settings necessary for creating mixed DLL are described in the previous article.
The mid-level component's
ViewFrameworkElemen are wrappers to the unmanaged MFC application. These components combine into
MfcAppAdapter is responsible for the initialization/termination of the encapsulated MFC application, the command interface to the application and the document opening. The MFC View created in hosted MFC application can be found with method
MfcAppAdapter.GetCreatedView() and can be hosted in
ViewCtrl (WinForms) or
ViewFrameworkElement (WPF). Mid-level components are not dependant on the actual MFC application or on the actual .NET/WPF Framework. The sample version supports SDI/MDI MFC applications, but it is possible to add support for other MFC application types: Dialog based and Multiple top-level documents.
The high level components are
FormsDemo (WinForms) and
WPFDemo (WPF). Both editors have two hosted MFC applications with documents: UmlEditor.dll + UmlEdi1.uml and DialogEditor.dll + DlgEdi1.dlg. Both editors support:
- Simply layout of hosted
FormsDemo) or hosted
UpdateUI and event handling of the
WPFDemo) in hosted MFC applications.
While the initialization of MFC application and the hosting of MFC View is solved relatively easily, Layout is one of the main problems of the integration MFC and WinForms/WPF. To support necessary Layout in a hosted View, the
CView interface is not enough, therefore I used the
CLayoutView interface. With this interface, I realized a relatively simple Layout in a described example. If you need another layout realization, you can override methods:
ViewCtrl.ScaleControl() and use another interface.
Layout problems are also problems with
WindowsFormsHost class. This class tries to realize the WPF Layout for hosted WinForms
Control. Unfortunately, I could not take advantage of
WindowsFormsHost even in simple cases. Is this the result of pure compatibility of WinForms and WPF Layout or simply programming bugs, I don't know. For example:
<FlowDocument TextAlignment="Left" Background="AliceBlue" >
TestCase1: change Zoom.
TestCase2: remove Background="Yellow" attribute from wrapped button.
<wf:Button Text="Windows Forms button" FlatStyle="Flat"/>
The first Test Case would introduce a cycle, the second - exception.
Thus, instead of
WindowsFormsHost classes, I used
ViewFrameworkElemen class for hosting View in WPF. In this case, we should implement the necessary WPF Layout instead of implementation of WinForms Layout and its "conversion" to WPF with
WindowsFormsHost. As well as in case of
ViewCtrl we can override methods:
ViewFrameworkElement. OnMeseareOverride() and
ViewFrameworkElement.ArrangeOverride() to realize any other Layout, for example, to support the resolution-independent layout.
For simplicity, I describe here hosting of simple MFC/Dialogs application in .NET Framework - without hosting of views and VS designer support. The purpose of this sample is to help you to start with your MFC application hosting. It consists of 8 steps which you need to create Visual Studio 2005 wizards MFC/Dialogs application "DialogWiz" and to host it in “FormsDemo_DialogWiz” WinForms .Net application. The resulted source code you can find in MfcAdapter 2.2 samples.
NOTE: Because MfcAdapter 2.2 does not supports
CWinAppEx, you can create this sample only in VS2005! If you use VS2010, please use the "DialogWiz" sample from MfcAdapter 2.2 samples.
- Create Visual C++ MFC Application "DialogWiz" with default project settings - Multiple document interface, No database support.
- Copy source code files
MfcCommand.cpp from resulted source code to you solution directory and add it to your "DialogWiz" project. Now we have this project tree:
- Change Project setting:
|Configuration Type ||Dynamic Library (.dll)|
|Additional Include Directories||"$(ProjectDir)"|
|Debug Information Format||Program Database (/Zi)|
|Enable C++ Exceptions||With SHE Exceptions (/EHa)|
|Enable Minimal Rebuild||No|
|Basic Runtime Checks||Default|
|Create/Use Precompiled Headers||Not Using Precompiled Headers|
|Debuggable Assembly||Yes (/ASSEMBLYDEBUG)|
- Change "CLR support" property of MfcCommand.cpp:
|Compile with Common Language Runtime Support||Common Language Runtime Support (/clr)|
- Change DialogWiz.cpp DialogWiz.h and MainForm.cpp MainForm.h as in resulted source code. I track all changes with comments:
//******AS update start**************************//
//******AS update end**************************//
Add to solution new Visual C# Windows Application " FormsDemo_DialogWiz ". Add reference to DialogWiz.dll, and to MfcAppAdapter.
- Overwrite files
Form1.resx from the resulted source code to our project.
- Set Debug Configuration and " FormsDemo_DialogWiz " project as StartUp Project. Press F5 - Good luck!
Because the MfcAdapter uses MFC library, you have to avoid mix different version of MfcAdapter assemblies (Debug and Release, different character set, different MFC or CLR versions). You can simply copy necessary Debug or Release assemblies by Post Build Event in project settings.
|MfcAdapter Control ||Type ||Support of MFC applications container ||Supported MFC Views |
CWnd, CView, CScrollView
CWnd, CView, CScrollView
|WPF||No ||CWnd, CView, CScrollView, CCtrlView, CListView, CTreeView, CEditView, CRichEditView |
All MfcAdapter classes suport the hosting of
CScrollView based customers views. You can directly embed a control object (like
CHeaderCtrl and so on+) or for example
COleDropTarget as class member in your class.
In any case don't use
CView::OnCreate for creating and initializing of view class members inherited from
CWnd. This code should be removed from the
OnCreate method to the
OnInitialUpdate. In this case, these members will be created after the view attached to the WinForms
Control or to
HwndHost element in WPF.
ViewFrameworkElement to support the hosting of
CRichEditView based customer’s views.
ViewFrameworkElementEx can host just as
CScrollView based customer’s views. But it can be used only for hosting single MFC application. See the sample “RowList“ from MfcAdapter samples.
The current version of the MfcAdapter does not support the hosting of
CFormView based views and
CWinAppEx based applications.
MfcAdapter source code compatible with x86, x64 Windows, MFC version from 7.1 (VS2003) any configuration (ASCII\Unicode\Mulibyte) and .Net from 2.0 to 4.5.
NOTE: For using MfcAdapter 2.2 Demo you need installed VS 2010.
MfcAdapter 2.2 does not need a special installation. After extraction from the archiv, You will have source code and executable programs of 5 MFC applications:
- "DialogWiz" - simple MFC application without views (only dialogs) created with VS 2005 wizard
- "DialogEditor" - DIY vector and dialog editor by Johan Rosengren (http://www.codeproject.com/)
- "UMLEditor" - revisiting the vector editor by Johan Rosengren (http://www.codeproject.com/)
- "Mesh" - A small VRML viewer using OpenGL and MFC (http://www.codeproject.com/)
- "RowList" - MFC sample of CListView, CLayoutView, CView
hosted in WinForms:
- FormsDemo_UmlEditor.exe - Container with hosted MFC applications "UmlEditor" and "DialogEditor"
- MdiFormsDemo.exe - Full version of the hosted "UmlEditor"
- SdiFormsDemo.exe - Full version of the hosted "DialogEditor"
- FormDemo_SimpleCtrl.exe - Simple test for the
FormsDemo_DialogWiz.exe - hosted "DialogWiz"
hosted in WPF:
- WpfDemo_UmlEditor.exe - Container with hosted MFC applications "UmlEditor" and "DialogEditor"
- WpfPageDemo_UmlEditor.exe - WPF
FlowDocument. Container with hosted MFC applications "UmlEditor" and "DialogEditor"
- WpfPageDemo_RowList.exe - hosted "RowList"
- WpfPageDemo_WrlViewer.exe - hosted VRML viewer
Simply run the necessary application.
NOTE: MfcAdapter 2.2 Demo support only one configuration: x86 Debug, Unicode, .Net 4.0.
After unzip, we have one VS 2010 solution - \Samples\Src\Samples.sln with all demo projects. All projects build outputs will be copied in the common execute directory \Samples\Src\Debug with necessary MfcAdapter dll's.
By reference error, simple repeat a build.
I tried to keep the encapsulated MFC code as short as possible, so I have not fixed some of the native problems of this code, for example, compiler warnings, an unhandled exception when opening a recent file that does not exist and others.
Host your MFC application
For host your MFC application use - x86 Debug Unicode .Net 4.0 version of MfcAdapter:
- MfcAppAdapter.dll, ViewControl.dll, ViewFrameworkElement.dll
- MfcAdapterAPI.chm, ProgrammingGuide.htm