65.9K
CodeProject 正在变化。 阅读更多。
Home

MfcAdapter - 非 OLE .NET/WPF MFC 应用程序容器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (12投票s)

2007 年 1 月 19 日

CPOL

8分钟阅读

viewsIcon

121464

downloadIcon

2988

如何基于在 WinForms 和 WPF 应用程序中托管 MFC 应用程序,构建非 OLE MFC 应用程序容器。

目录

引言

在我第一篇文章 "在 WinForms 和 WPF 应用程序中托管 MFC MDI 应用程序" 的电子邮件中,我收到一个问题 - "使用描述的技术是否可以构建 MFC 应用程序的容器?" 这个任务导致了架构的一些小改动,以使组件更加灵活。这样的工作总是令人愉快的,这也是本文的主要动机。另一方面,结果看起来像一个 OLE 容器,但我没有创建 COM 对象就完成了!

我使用两个应用程序作为示例:Johan Rosengren 的 UmlEditor (MDI) 和 DialogEditor (SDI)。我们可以使用 MfcAdapter 将这两个应用程序嵌入 WinForms 或 WPF 框架中。为简单起见,我使用了基于 RichTextBox 的演示编辑器 "FormsDemo" (WinFroms) 和 "WPFDemo" (WPF) 作为这种容器。

容器的架构

主要的变化是将 MfcAdapter 和 MFC 应用程序分成单独的组件。在这种情况下,我们将拥有一个完全独立于实际 MFC 应用程序的 MfcAdapter

在所述架构中,低级 .NET 组件是一个混合(托管/非托管)DLL,其中包含一个 MFC 应用程序和托管类 ModuleState

ModuleState 是 MFC 应用程序的非托管 AFX_MODULE_STATE 的托管指针。使用 static 方法 ModuleState.GetModuleState()MfcAdapter 或其他 C++/CLI 组件可以从必要的混合 DLL 加载 AFX_MODULE_STATE。之后,MfcAdapter 可以切换到这个 AFX_MODULE_STATE 并使用被托管 MFC 应用程序的非托管 API。此外,混合 MFC DLL 还提供了 CommandID 的托管等效项,这些项可以在 MFC 应用程序中进行处理。

要在 WinForms/WPF 框架中托管 MFC 应用程序,如我在第一篇文章中所述,我们应该

  • 保留一个不可见的 CMainFrame 和一个已创建的 CView。我已经更新了应用程序初始化,并在重写的文档模板中将 bMakeVisible 参数设置为 "false" 以实现此目的。好消息是,我们不需要像以前版本的 MfcAdapter 那样重写 CDocManager 或更改文档。
  • 保留被托管对话框的模态属性。将 MFC MainFrame 窗口创建为 Framework MainForm 窗口的子窗口。在 MFC MainFrame 中使用 CNotifyHook 来支持外部框架中的模态 MFC 对话框。
  • 自动布局支持。我们必须在托管视图中实现 CLayoutView 类的一些方法:SetPrefferedSize()GetPreferredSize()Scale()

创建混合 DLL 所需的 MFC 代码更改和项目设置的详细描述在上一篇文章中。

中级 组件 MfcAppAdapterViewCtrlViewFrameworkElemen 是非托管 MFC 应用程序的包装器。这些组件组合成 MfcAdapter

MfcAppAdapter 负责封装的 MFC 应用程序的初始化/终止、应用程序的命令接口和文档打开。可以在 ViewCtrl (WinForms) 或 ViewFrameworkElement (WPF) 中托管的 MFC 视图可以通过方法 MfcAppAdapter.GetCreatedView() 找到。中级组件不依赖于实际的 MFC 应用程序或实际的 .NET/WPF Framework。示例版本支持 SDI/MDI MFC 应用程序,但也可以添加对其他 MFC 应用程序类型的支持:基于对话框和多顶层文档。

高级 组件是 FormsDemo (WinForms) 和 WPFDemo (WPF)。这两个编辑器都包含两个托管的 MFC 应用程序及其文档:UmlEditor.dll + UmlEdi1.umlDialogEditor.dll + DlgEdi1.dlg。两个编辑器都支持

  • 简单布局托管的 Controls (FormsDemo) 或托管的 FrameworkElements (WPFDemo)
  • 托管 MFC 应用程序中的 ToolStrip (FormsDemo) 或 ToolBar (WPFDemo) 的 UpdateUI 和事件处理。

布局

虽然 MFC 应用程序的初始化和 MFC 视图的托管相对容易解决,但布局是 MFC 与 WinForms/WPF 集成中的主要问题之一。为了支持托管视图中的必要布局,CView 接口是不够的,因此我使用了 CLayoutView 接口。通过这个接口,我在描述的示例中实现了相对简单的布局。如果您需要其他布局实现,可以重写方法:ViewCtrl.GetPrefferedSize()ViewCtrl.ScaleControl() 并使用其他接口。

布局问题也是 WindowsFormsHost 类的问题。该类试图为托管的 WinForms Control 实现 WPF 布局。不幸的是,即使在简单的情况下,我也无法利用 WindowsFormsHost。这是 WinForms 和 WPF 布局纯粹兼容性的结果,还是仅仅是编程错误,我不知道。例如

<!--Test WindowsFormsHost-->
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms">

<FlowDocumentPageViewer>
  <FlowDocument TextAlignment="Left" Background="AliceBlue" >
    <Paragraph>
      <Bold>Test WindowsFormsHost</Bold>
    </Paragraph>
    <Paragraph>
      TestCase1: change Zoom.
    </Paragraph>
    <Paragraph>
      TestCase2: remove Background="Yellow" attribute from wrapped button.
    </Paragraph>
    <Paragraph>
      <Button>WPF button</Button>
    </Paragraph>
    <Paragraph>
      <WindowsFormsHost Background="Yellow">
      <wf:Button Text="Windows Forms button" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Paragraph>
  </FlowDocument>
</FlowDocumentPageViewer>
</Page>

第一个测试用例会引入一个循环,第二个会引入一个异常。

因此,我使用了 ViewFrameworkElemen 类来代替 ViewCtrlWindowsFormsHost 类来在 WPF 中托管视图。在这种情况下,我们应该实现必要的 WPF 布局,而不是实现 WinForms 布局并用 WindowsFormsHost "转换" 到 WPF。与 ViewCtrl 一样,我们可以重写方法:ViewFrameworkElement.OnMeseareOverride()ViewFrameworkElement.ArrangeOverride() 来实现任何其他布局,例如支持分辨率无关的布局。

快速入门:托管简单的 MFC/对话框应用程序

为了简单起见,我在此描述了在 .NET Framework 中托管简单的 MFC/对话框应用程序 - 未托管视图和 VS 设计器支持。此示例的目的是帮助您开始托管 MFC 应用程序。它包含 8 个步骤,您需要创建 Visual Studio 2005 向导 MFC/对话框应用程序 "DialogWiz" 并在 "FormsDemo_DialogWiz" WinForms .Net 应用程序中托管它。最终的源代码可以在 MfcAdapter 2.2 示例中找到。

注意: 由于 MfcAdapter 2.2 不支持 CWinAppEx,因此您只能在 VS2005 中创建此示例!如果您使用 VS2010,请使用 MfcAdapter 2.2 示例中的 "DialogWiz" 示例。

 

 

使用公共语言运行时支持进行编译公共语言运行时支持 (/clr)

 

  1. 创建 Visual C++ MFC 应用程序 "DialogWiz",使用默认项目设置 - 多文档界面,无数据库支持。
  2. NotifyHook.cppNotifyHook.hCHostApp.hMfcCommand.cpp 源文件从最终源代码复制到您的解决方案目录,并将其添加到 "DialogWiz" 项目。现在我们有了这个项目树。

  3. 更改项目设置

     

    配置类型动态库 (.dll)
    其他包含目录"$(ProjectDir)"
    调试信息格式程序数据库 (/Zi)
    启用 C++ 异常带 SHE 异常 (/EHa)
    启用最小重新生成
    基本运行时检查默认值
    创建/使用预编译头文件不使用预编译头文件
    输出文件$(OutDir)\$(ProjectName).dll
    可调试程序集是 (/ASSEMBLYDEBUG)
  4. 更改 MfcCommand.cpp 的 "CLR 支持" 属性
  5. 按最终源代码中的方式更改 DialogWiz.cpp、DialogWiz.h 和 MainForm.cpp、MainForm.h。我用注释跟踪了所有更改。

    <code>//******AS update start**************************//

    <code>//******AS update end**************************//

  6. 向解决方案添加新的 Visual C# Windows 应用程序 "FormsDemo_DialogWiz"。添加对 DialogWiz.dll 和 MfcAppAdapter 的引用。
  7. 用最终源代码中的 Form1.csForm1.Designer.csForm1.resx 文件覆盖我们的项目。
  8. 设置调试配置并将 "FormsDemo_DialogWiz" 项目设置为启动项目。按 F5 - 祝你好运!

构建先决条件

由于 MfcAdapter 使用 MFC 库,您必须避免混合不同版本的 MfcAdapter 程序集(Debug 和 Release,不同的字符集,不同的 MFC 或 CLR 版本)。您可以通过项目设置中的生成后事件简单地复制必要的 Debug 或 Release 程序集。

兼容性

 

MfcAdapter 控件类型支持 MFC 应用程序容器支持的 MFC 视图
ViewCtrlWinFormsCWnd, CView, CScrollView
ViewFrameworkElementWPFCWnd, CView, CScrollView
ViewFrameworkElementExWPFCWnd, CView, CScrollView, CCtrlView, CListView, CTreeView, CEditView, CRichEditView 

所有 MfcAdapter 类都支持托管 CWndCView 或基于 CScrollView 的客户视图。您可以直接嵌入控件对象(如 CListCtrlCHeaderCtrl 等)或例如 COleDropTarget 作为类成员。

无论如何,请不要在 CView::OnCreate 中创建和初始化继承自 CWnd 的视图类成员。此代码应从 OnCreate 方法移至 OnInitialUpdate。这样,这些成员将在视图附加到 WinForms Control 或 WPF 中的 HwndHost 元素之后创建。

ViewFrameworkElementEx 扩展了 ViewFrameworkElement 以支持托管基于 CCtrlViewCListViewCTreeViewCEditViewCRichEditView 的客户视图。ViewFrameworkElementEx 就像 ViewFrameworkElement 一样,可以托管基于 CWndCViewCScrollView 的客户视图。但它只能用于托管单个 MFC 应用程序。请参阅 MfcAdapter 示例中的 "RowList" 示例。

MfcAdapter 的当前版本不支持托管基于 CFormView 的视图和基于 CWinAppEx 的应用程序。

MfcAdapter 源代码兼容 x86、x64 Windows、MFC 版本 7.1 (VS2003) 任何配置(ASCII\Unicode\Mulibyte)以及 .Net 2.0 至 4.5。

部署和安装

注意: 要使用 MfcAdapter 2.2 演示版,需要安装 VS 2010。

MfcAdapter 2.2 不需要特殊安装。从存档解压后,您将获得 5 个 MFC 应用程序的源代码和可执行程序。

  • "DialogWiz" - 使用 VS 2005 向导创建的简单 MFC 应用程序(仅对话框,无视图)。
  • "DialogEditor" - Johan Rosengren 的 DIY 矢量和对话框编辑器 (https://codeproject.org.cn/)
  • "UMLEditor" - Johan Rosengren 的矢量编辑器重制版 (https://codeproject.org.cn/)
  • "Mesh" - 一个使用 OpenGL 和 MFC 的小型 VRML 查看器 (https://codeproject.org.cn/)
  • "RowList" - CListView、CLayoutView、CView 的 MFC 示例。

托管在 **WinForms** 中

  • FormsDemo_UmlEditor.exe - 包含托管 MFC 应用程序 "UmlEditor" 和 "DialogEditor" 的容器
  • MdiFormsDemo.exe - 托管 "UmlEditor" 的完整版本
  • SdiFormsDemo.exe - 托管 "DialogEditor" 的完整版本
  • FormDemo_SimpleCtrl.exe - CScrollViewCListCtrl 的简单测试
  • FormsDemo_DialogWiz.exe - 托管 "DialogWiz"

托管在 **WPF** 中

  • WpfDemo_UmlEditor.exe - 包含托管 MFC 应用程序 "UmlEditor" 和 "DialogEditor" 的容器
  • WpfPageDemo_UmlEditor.exe - WPF FlowDocument。包含托管 MFC 应用程序 "UmlEditor" 和 "DialogEditor" 的容器
  • WpfPageDemo_RowList.exe - 托管 "RowList"
  • WpfPageDemo_WrlViewer.exe - 托管 VRML 查看器

只需运行相应的应用程序。

源代码

注意: MfcAdapter 2.2 演示版仅支持一种配置:x86 Debug、Unicode、.Net 4.0。

解压后,我们将获得一个 VS 2010 解决方案 - \Samples\Src\Samples.sln,其中包含所有演示项目。所有项目的构建输出将复制到公共可执行目录 \Samples\Src\Debug,并包含必要的 MfcAdapter dll。

如果出现引用错误,请简单地重新构建。

我尽量使封装的 MFC 代码尽可能简洁,因此我没有修复此代码中的一些原生问题,例如编译器警告、打开不存在的最近文件时未处理的异常等。

托管您的 MFC 应用程序

要托管您的 MFC 应用程序,请使用 - x86 Debug Unicode .Net 4.0 版本的 MfcAdapter

\Debug

 

  • MfcAppAdapter.dll, ViewControl.dll, ViewFrameworkElement.dll 

 

\Include

 

  • HostApp.h, LayoutView.h 

 

帮助

 

  • MfcAdapterAPI.chm, ProgrammingGuide.htm 

 

© . All rights reserved.