继Microsoft的Source generation for ComWrappers文章之后,我使用GeneratedComInterfaceAttribute属性在Visual Studio 2022中创建了一个简单的.NET 8 Class Library项目.我的类基于this other Stack Overflow question中描述的类似类,其中使用了.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:

project output

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

enter image description here enter image description here

然后,使用VB 6 IDE的引用窗口或OLViewer,我不会将ComHostTest程序集视为可用的COM类型库:

enter image description here enter image description here

知道为什么吗?

我读过this very similar question,其中该人也使用.NET 8,但不使用GeneratedComInterfaceProperty.


编辑

我根据西蒙·马希尔的 comments 调整了我的代码:

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 TSB文件,我将其包含在我的.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>

仍然没有运气在VB 6 IDE中看到它,但我一定很接近.

推荐答案

根据Simon Mattan的 comments 和他对this similar question的回答,我设法让该库显示在VB 6的参考文献列表中.

编写接口和类

首先,简单的部分.以下是接口和类的代码:

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(工具创建收件箱)中的"创建收件箱"窗口

项目文件(.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>

配置管理器中的Set the project platform to x86.这将编译VB 6所期望的32位DLC.

您应该能够构建这个项目并获得ComHostTest.comhost.dll分.这是一个COM server:

COM服务器是向客户端提供服务的任何对象;这些 服务采用COM接口实现的形式,可以 由任何能够获取指向其中一个的指针的客户端调用 服务器对象上的接口.

Register this DLL使用regsvr32.这会将IComHostTestComHostTest GUID写入Windows注册表.从提升的命令提示符:

regsvr32 ComHostTest.comhost.dll

此时,您可以使用[ComImport][CoClass]属性激活COM类from a .NET project,但我们需要进一步让VB 6识别该类.

创建和注册TSB

要让VB 6引用您的程序集,您首先需要为其创建一个类型库文件(TSB).如果您还没有它,请从GitHub获取dscom32.exe.您可以从dSPACE-group/dscom Releases处获取编译版本.此工具将从您的DLC生成一个TSB文件:

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

然后,使用相同的工具注册TSB:

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

这应该返回:

类型库注册成功

在VB 6中添加引用

最后,在VB 6中,打开"引用"窗口并找到您的库:

enter image description here

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

enter image description here

运行VB 6代码以确保一切正常工作.此时你应该已经准备好出发了.

如果出现以下错误,则表明您尚未正确注册<your project>.comhost.dll:

enter image description here

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

更新您的DLC

如果您需要更改DLC:

  1. 如果接口没有更改,您只需要重建您的DLC.
  2. 如果接口已更改,您将需要创建一个新的TSB并使用dsom 32注册它.

注意到

  1. 注册TLR和<your project>.comhost.dll的顺序并不重要,但这两者都必须发生.
  2. 问题文本中提到的项目文件中的<ComHostTypeLibrary Include="ComHostTest.tlb" Id="1" />行没有必要.
  3. 这也适用于WPF Class Library项目.

所有的功劳都归功于西蒙·麦蒂.

Csharp相关问答推荐

我如何才能获得被嘲笑班级的私有成员?

将修剪声明放入LINQ中

有没有办法把+02:00转换成TimeSpan?""

为什么Blazor值在更改后没有立即呈现?

不仅仅是一个简单的自定义按钮

JsonSerializer.Deserialize<;TValue>;(String,JsonSerializerOptions)何时返回空?

在调整大小的控件上绘制

如何在C#中使用Postman中的本地IP向本地主机上运行的本地API发出请求

Blazor在FluentButton onClick事件上设置参数

当前代码Cosmos DB 3.37.1:PartitionKey key key mismatch exception

交替的奇数

在try 使用访问服务器上的文件夹时,如何解决CORS错误.NET核心API

异步任务调用程序集

如何返回具有泛型的类?

Postgres ENUM类型在第一次运行时对Dapper不可见

在集成测试中可以在模拟InMemory数据库中设定数据种子

C#LINQ延迟执行和嵌套方法

如何从非异步任务中正确返回TypeResult

如何在Polly重试策略成功之前将HttpClient请求排队?

Visual Studio 17.8.0制表符自动完成问题--三缩进