.NET 8 COM 类使用 GenerationComInterfaceAttribute 对 VB6/VBA 或 OLEViewer 不可见

问题描述 投票:0回答:1

按照 Microsoft 的 ComWrappers 源生成 文章,我使用 GenerateComInterfaceAttribute 属性在 Visual Studio 2022 中创建了一个简单的 .NET 8 类库项目。我的类基于另一个 Stack Overflow 问题中描述的类似类,其中使用了 .NET 5。

这是默认的代码

Class1.cs
:

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace ComHostTest
{
    [GeneratedComClass]
    [Guid("63C60D62-317F-4BAB-BB20-0AB41F34A345")]
    public partial class Class1
    {
        public string SayHello() => "Hello World from .NET " + RuntimeInformation.FrameworkDescription;
    }
}

这是我的项目文件:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x86</PlatformTarget>
        <EnableComHosting>true</EnableComHosting>
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
        <Platforms>AnyCPU;x86</Platforms>
    </PropertyGroup>

</Project>

我的构建配置和 PlatformTarget 设置为 x86。该项目正确构建并生成

ComHostTest.comhost.dll
:

使用提升的命令提示符,我成功注册了 comhost.dll:

然后,使用 VB6 IDE 的“引用”窗口或 OLEViewer,我没有看到 ComHostTest 程序集作为可用的 COM 类型库:

知道为什么吗?

我已经读过这个非常相似的问题,其中该人也使用 .NET 8,但不使用 GenerationComInterfaceAttribute。


编辑

我根据 Simon Mourier 的评论调整了我的代码:

using System.Runtime.InteropServices;

namespace ComHostTest
{

    [ComVisible(true)]
    [Guid("72433A8C-941E-4876-8CC2-15F6F4235F32")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IComHostTest
    {
        public string SayHello();
    }

    [ComVisible(true)]
    [Guid("63C60D62-317F-4BAB-BB20-0AB41F34A345")]
    [ClassInterface(ClassInterfaceType.None)]
    public class ComHostTest : IComHostTest
    {
        public string SayHello() => "Hello World from .NET " + RuntimeInformation.FrameworkDescription;
    }

}

项目文件未被触及,因为它已经包含了

<EnableComHosting>true</EnableComHosting>

我从 GitHub 下载了 dscom32 版本,然后从 Visual Studio 中的 Developer PowerShell 窗口执行了以下命令:

dscom32 tlbexport "D:\.NET Projects\Development\COM host\ComHostTest\bin\x86\Debug\net8.0\ComHostTest.dll"

这生成了一个 ComHostTest TLB 文件,我将其包含在我的 .csproj 文件中:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x86</PlatformTarget>
        <EnableComHosting>true</EnableComHosting>
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
        <Platforms>AnyCPU;x86</Platforms>
    </PropertyGroup>

    <ItemGroup>
        <ComHostTypeLibrary Include="ComHostTest.tlb" Id="1" />
    </ItemGroup>

</Project>

仍然没有运气在 VB6 IDE 中看到它,但我一定很接近了。

c# vba .net-core vb6 com-interop
1个回答
2
投票

根据 Simon Mourier 的评论和他对类似问题的回答,我设法让该库显示在 VB6 的参考列表中。

编写接口和类

首先,简单的部分。这是接口和类的代码:

using System.Runtime.InteropServices;

    namespace ComHostTest
    {
    
        [ComVisible(true)]
        [Guid("72433A8C-941E-4876-8CC2-15F6F4235F32")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IComHostTest
        {
            public string SayHello();
        }
    
        [ComVisible(true)]
        [Guid("63C60D62-317F-4BAB-BB20-0AB41F34A345")]
        [ClassInterface(ClassInterfaceType.None)]
        public class ComHostTest : IComHostTest
        {
            public string SayHello() => "Hello World! from .NET " + RuntimeInformation.FrameworkDescription;
        }
    
    }

您可以使用 Visual Studio 中的“创建 GUID”窗口(“工具”>“创建 GUID”)为 Guid() 属性生成新值。

项目文件(

.csproj
):

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x86</PlatformTarget>
        <EnableComHosting>true</EnableComHosting>
        <Platforms>AnyCPU;x86</Platforms>
    </PropertyGroup>

</Project>

在配置管理器中将项目平台设置为x86。这将编译一个 32 位 DLL,这正是 VB6 所期望的。

您应该能够构建这个项目并获得

ComHostTest.comhost.dll
使用 regsvr32
 注册此 DLL
。这将向 COM 注册您的 .NET 类。

此时,您可以使用 [ComImport]

[CoClass]
属性从 .NET 项目
激活 COM 类,但我们需要进一步让 VB6 识别该类。

创建并注册TLB

要让 VB6 引用您的程序集,您首先需要为其创建一个类型库文件 (TLB)。如果您还没有,请从 GitHub 获取

dscom32.exe

。您可以从
dSPACE-group/dscom Releases获取编译版本。该工具将从您的 DLL 生成 TLB 文件:

dscom32 tlbexport "D:\.NET Projects\Development\COM host\ComHostTest\bin\x86\Debug\net8.0\ComHostTest.dll"
然后,使用相同的工具来注册TLB:

dscom32 tlbregister "D:\.NET Projects\Development\COM host\ComHostTest\bin\x86\Debug\net8.0\ComHostTest.tlb"
这应该返回:

类型库注册成功

在 VB6 中添加参考

最后,在 VB6 中,打开“参考文献”窗口并找到您的库:

您现在应该能够在 IntelliSense 中查看并创建类的实例:

运行 VB6 代码以确保一切正常。现在你应该可以走了。

如果出现以下错误,则说明您尚未正确注册

<your project>.comhost.dll

运行时错误'-2147221164(80040154)':类未注册

更新你的DLL

如果您需要更改 DLL:

    如果接口没有改变,你只需要重建你的DLL。
  1. 如果接口发生变化,您将需要创建一个新的TLB并使用dscom32注册它。
注释

    注册 TLB 和
  1. <your project>.comhost.dll
     的顺序并不重要,但它们都必须发生。
  2. 问题文本中提到的项目文件中的
  3. <ComHostTypeLibrary Include="ComHostTest.tlb" Id="1" />
    行不是必需的。
  4. 这也适用于 WPF 类库项目。
所有功劳都归功于西蒙·穆里尔。

© www.soinside.com 2019 - 2024. All rights reserved.