如何将 WPF 控件包装为 ActiveX 组件

如何将 WPF 控件包装为 ActiveX 组件

前面的一篇文章中介绍了 如何将WPF控件嵌入Win32程序中,其要求 Win32 程序支持 C++/CLR(托管代码)。然而在我们实际工程中,要使现有的 Win32/MFC 项目支持 CLR,可能涉及到较大的改动。那么,能不能在 纯非托管程序 中嵌入 WPF 控件呢?答案当然是肯定的,那就是 COM/ActiveX 组件。

COM是 Component Object Model(组件对象模型)的缩写,Microsoft的许多技术,如 ActiveX , DirectX 以及 OLE 等都是基于 COM 而建立起来的。请自行百度了解 COM/ActiveX 的基本概念。

实现原理

理论上 COM/ActiveX 可以搭建起 WPFMFC 之间的桥梁,实际操作时发现 WPF 生成的 ActiveX 并不是有效的 COM 组件,无法集成到 MFC 界面中。好在 WinForm 能够生成有效的 COM 组件,我们可以先将 WPF 控件集成到 WinForm 控件中,然后将 WinForm 控件编译成 ActiveX 组件。

开发环境

  • Visual Studio 2017
  • .NET Framework 4.5
  • MFC / C++
  • WPF / WinForm / C#

基本步骤

  1. 创建 WPF & WinForm 控件工程
  2. 将 WinForm 控件配置成 COM/ActiveX 组件
  3. 编写 COM 组件自动注册代码
  4. 在 MFC 中集成 ActiveX 组件

1. 创建 WPF & WinForm 控件工程

此处不用赘述,先在 Visual Studio 中创建 WPF User Control Library 工程和 Windows Forms Control Library 工程;然后在 WPF 工程中创建名为 MyWpfControlUser Control (WPF) 控件,在 WinForm 工程中创建名为 MyWinFormControlUser Control 控件;最后将 MyWpfControl 添加到 MyWinFormControl 中,效果如下图所示。

2. 将 WinForm 控件配置成 COM/ActiveX 组件

首先,进入 MyWinFormControl项目属性 设置界面,找到 Application -> Assembly Infomation,勾选底部的 Make assembly COM-visible 选项。

然后,为 MyWinFormControl 添加 ProgIdClassInterface 两个特性,分别用作标识组件名称和指定接口生成策略。

[ProgId("WinFormControl.MyWinFormControl")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public partial class MyWinFormControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
    }
    ......
}

3. 编写 COM 组件注册代码

通过如上配置,编译出来的 MyWinFormControl 便是一个 COM/ActiveX 组件,我们可以通过 regSvr32 命令来手动注册。为了方便调试,也可编写如下代码来实现编译后的自动注册,以及清理后的自动反注册。由于 COM 组件的注册涉及到注册表操作,所以需要以管理员权限运行 Visaul Studio

首先,在 项目属性 界面下的 Build 栏中勾选 Register for COM interop 选项。

然后,在 MyWinFormControl 所在内中添加 RegisterClassUnregisterClass 两个静态方法,注意分别标记 ComRegisterFunctionComUnregisterFunction 特性。

///	<summary>
///	Register the class as a	control	and	set	it's CodeBase entry
///	</summary>
///	<param name="key">The registry key of the control</param>
[ComRegisterFunction()]
public static void RegisterClass(string key)
{
    // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
    StringBuilder sb = new StringBuilder(key);
    sb.Replace(@"HKEY_CLASSES_ROOT\", "");

    // Open the CLSID\{guid} key for write access
    RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
    if (k == null)
    {
        throw new NullReferenceException();
    }

    // And create the 'Control' key - this allows it to show up in 
    // the ActiveX control container 
    RegistryKey ctrl = k.CreateSubKey("Control");
    ctrl?.Close();

    // Next create the CodeBase entry - needed if not string named and GACced.
    RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
    inprocServer32?.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
    inprocServer32?.Close();

    // Finally close the main key
    k.Close();
}

///	<summary>
///	Called to unregister the control
///	</summary>
///	<param name="key">Tke registry key</param>
[ComUnregisterFunction()]
public static void UnregisterClass(string key)
{
    StringBuilder sb = new StringBuilder(key);
    sb.Replace(@"HKEY_CLASSES_ROOT\", "");

    // Open HKCR\CLSID\{guid} for write access
    RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
    if (k == null)
    {
        return;
    }

    // Delete the 'Control' key, but don't throw an exception if it does not exist
    k.DeleteSubKey("Control", false);

    // Next open up InprocServer32
    RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);

    // And delete the CodeBase key, again not throwing if missing 
    inprocServer32?.DeleteSubKey("CodeBase", false);
    inprocServer32?.Close();

    // Finally close the main key 
    k.Close();
}

编译 MyWinFormControl 项目,一个名为 WinFormControl.MyWinFormControlAxtiveX 组件将被自动注册到系统中。

4. 在 MFC 中集成 ActiveX 组件

进入 MFC 项目,在界面上单击鼠标右键,选择 Insert ActiveX Control...,在弹出的 Insert ActiveX Control 窗口中选择 WinFormControl.MyWinFormControl

另外,还可以使用 tstcon32.exe 来测试 ActiveX 组件。

方案总结

要实现 Win32/MFC 内嵌 WPF 控件,除了使用前面文章中介绍的 C++/CLR 方案外,还可以使用本文的 ActiveX 方案。比较而言,ActiveX 方案更加灵活自由,对 Win32/MFC 项目无特殊要求。

源码:https://github.com/Iron-YeHong/WPFInterop

参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ironyho

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值