mfc 调用 wpf 组件

MFC 调用 WPF 组件

在最近的开发中,发现一件有趣的事情,不得去感叹巨硬🐮🍺的技术。将 WPF 组件嵌入到 Win32 程序中。

1. 设置 MFC 项目使用 CLR 去构建

实现 native C++ 与 managed .NET 代码之间的相互可操作性最好的方法就是将项目构建成 managed C++。打开项目的配置属性,在General下,有一个选项“Common Language Runtime support”。将其设置为“Common Language Runtime Support / clr”。

2. 将 WPF 程序集添加到项目依赖中

在解决方案资源管理器中右键单击项目,然后选择“引用”。单击“添加新引用”。在 .NET 选项卡下,添加WindowsBase,PresentationCore,PresentationFramework 和 System。在添加任何引用后重新构建项目以便确保它们能被成功引用到项目中。

3. 在 MFC 应用程序上设置 STAThreadAttribute 属性

WPF 要求在主 UI 线程上设置STAThreadAttribute。通过转到项目的“配置属性”来设置此项。在“连接器”-> “高级”下,有一个名为“CLR Thread Attribute”的选项。将其设置为“STA threading attribute”。

4. 创建 HwndSource 实例以包装 WPF 组件

System::Windows::Interop::HwndSource 是一个用于处理 MFC 和 .NET 组件之间的交互的 .NET 类。使用下面的代码去创建:

System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew     System::Windows::Interop::HwndSourceParameters("MyWindowName");
sourceParams->PositionX = x;
sourceParams->PositionY = y;
sourceParams->ParentWindow = System::IntPtr(hWndParent);
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD;

System::Windows::Interop::HwndSource^ source = gcnew System::Windows::Interop::HwndSource(*sourceParams);
source->SizeToContent = System::Windows::SizeToContent::WidthAndHeight;

将 HWND 成员变量添加到 dialog 类,然后赋值:m_hWnd =(HWND)source-> Handle.ToPointer();

source 对象和关联的 WPF content 将保持存在,直到调用 ::DestroyWindow(m_hWnd) 方法

5. 将 WPF 控件添加到 HwndSource 包装器

System::Windows::Controls::WebBrowser^ browser = gcnew System::Windows::Controls::WebBrowser();

browser->Height = height;
browser->Width = width;
source->RootVisual = browser;

6. 保持对 WPF 对象的引用

由于 browser 变量在退出创建函数后将会无法访问,这需要以某种方式保持对变量的引用。因为托管对象不能是非托管对象的成员,为此可以使用 gcroot 的包装器模板来完成工作。

在 dialog 类中添加一个成员变量:

#include <vcclr.h>
gcroot<System::Windows::Controls::WebBrowser^> m_webBrowser;

然后在第五步的代码加上下面一句:

m_webBrowser = browser;

现在就可以通过 m_webBrowser 访问 WPF 组件里面的属性和方法了。