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. 如果需要,可以使用 ComRegisterFunctionComUnregisterFunction 属性自定义程序集注册。 如果您计划注册基于 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 类中定义两个静态方法并将 ComRegisterFunctionComUnregisterFunction 属性应用于它们来实现:

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 的功能。

Go Top