目录

COM/ActiveX

DotNetBrowser 不支持将其功能作为 COM 组件或 ActiveX 控件公开。

但如果您需要将 DotNetBrowser 与只能使用 OLE/COM/ActiveX 的应用程序集成,您可以考虑包装您需要的功能,然后将这些包装器公开给该应用程序。 .NET Framework 和最新版本的 .NET(从 .NET Core 3.0 开始)都支持与 COM 库进行互操作。 因此,可以在 VB6、VBA、VBScript 等中访问 DotNetBrowser 提供的所有 Chromium 功能。

以下是对这一想法的一般描述:

  1. 设计并声明一组公开您所需功能的 COM 接口。 这些接口可以放在一个单独的项目中。 使用 ComVisible 属性来控制特定类和接口的可访问性。
  2. 在这些接口的实现中,初始化 DotNetBrowser 并执行您需要的所有操作。
  3. 如果需要,可以使用 ComRegisterFunction 和 ComUnregisterFunction 属性自定义程序集注册。 如果您计划注册基于 DotNetBrowser 功能的 ActiveX 控件,这似乎是必要的。
  4. 构建程序集并使用程序集注册工具 (regasm.exe) 对其进行注册。

在此之后,相应的条目将出现在 Windows 注册表中,该包装器将对 COM 客户端可用。

包装 DotNetBrowser 功能并将其公开给 COM 客户端的示例项目的代码在 GitHub 存储库中作为 Visual Studio 项目提供: C#, VB.NET

下文将详细介绍该示例的实现过程,并解释其中最重要的部分。

实现 

声明 COM 接口 

有几种方法可以在 .NET 中声明 COM 接口。 例如,您可以考虑在类上使用 ClassInterface 属性,向 COM 客户端公开其所有公共方法、属性、字段和事件。 在该示例中,使用了一种不同的方法——整个程序集被标记为ComVisible,接口被显式声明并公开。 这种方法有助于更好地控制向 COM 公开的内容。 接口实现被声明为内部类。 例如:

接口:

[Guid("D620EC2F-03E8-4C1A-9FF9-3A7B44590F54")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IComEngine
{
    [DispId(1)]
    void Initialize();

    [DispId(2)]
    void Dispose();

    [DispId(3)]
    IComBrowser CreateBrowser();
}

这个示例接口提供了三个方法 - 其中两个可用于控制包装的 IEngine 实例的生命周期,第三个用于创建 IBrowser 实例并将相应的 COM 包装器返回给客户端。

您还可以考虑将 ComVisible 属性应用于特定的类和接口,而不是将其应用于整个程序集。 在这种情况下,只有标有该属性的类和接口才能供 COM 客户端使用。 所有其他公共类型都不会公开。

实现 COM 接口 

这是上一节中提到的接口的示例实现:

实现:

[Guid("DAE7A4AC-2D70-4830-81D8-3D7E5D8A7981")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("DotNetBrowser.ComWrapper.Engine")]
public class EngineWrapper : IComEngine
{
    private IEngine engine;
    private bool initialized;

    #region Methods

    public IComBrowser CreateBrowser() => new BrowserImpl(engine.CreateBrowser());

    public void Dispose()
    {
        if (initialized)
        {
            engine?.Dispose();
            engine = null;
            initialized = false;
        }
    }

    public void Initialize()
    {
        if (!initialized)
        {
            engine = EngineFactory.Create(new EngineOptions.Builder
            {
                RenderingMode = RenderingMode.OffScreen
            }.Build());
            initialized = true;
        }
    }

    #endregion
}

在本例中,该实现是公开的,并指定了 ProgID - 因此,相应的 coclass 将向 COM 公开,并使用 ProgID 来引用它。

自定义程序集注册 

该示例项目还提供了 ComBrowserView 类 - 一个用于 WinForms BrowserView 的包装器,可用作独立的 ActiveX 控件。 为了使其可识别为 ActiveX 控件,需要在相应类型的注册过程中添加一些自定义注册表项。 这可以通过在 ComBrowserView 类中定义两个静态方法并将 ComRegisterFunction 和 ComUnregisterFunction 属性应用于它们来实现:

public partial class ComBrowserView : UserControl, IComBrowserView
{
    // ...

    [EditorBrowsable(EditorBrowsableState.Never)]
    [ComRegisterFunction]
    private static void Register(Type t)
    {
        ControlRegistration.RegisterControl(t);
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    [ComUnregisterFunction]
    private static void Unregister(Type t)
    {
        ControlRegistration.UnregisterControl(t);
    }
}

ControlRegistration.RegisterControl 实现向相应的 CLSID 注册表键添加了几个子键 - 其中最重要的是 Control 键,它允许自定义控件显示在 ActiveX 控件容器中. 其他子键定义了应使用的控制激活方式、工具箱图标、类型库 GUID 等。

构建项目并注册程序集 

要在构建期间注册程序集,请在示例项目中启用 “Register for COM Interop” 选项。 这似乎有助于调试执行。

作为结果,TLB 就会自动生成并注册。 清理项目会导致注销所有组件。

请检查您尝试集成的应用程序的位数。 如果您的应用程序是 64 位的,而控件仅为 32 位应用程序注册 (在这种情况下,注册表项是在 HKEY_CLASSES_ROOT\WOW6432Node\ 下创建的),则此应用程序将无法访问该控件。 如果应用程序是 32 位的,而控件仅为 64 位应用程序注册,则会出现同样的情况。

总结 

所述方法似乎有助于创建解决方案,为使用 COM 对象或嵌入 ActiveX 控件的应用程序提供基于 Chromium 的功能。