.NET 8 exposing to VB6 using COM

问题

我们有一个大型应用程序,其中有大量的GUI代码在VB6中,逻辑主要在. NET Framework 4.7.2库中.现在,我们想转移到. NET 8,并在使用COM向VB6公开库时遇到困难:

  1. Set oObject = New COObject不工作(VB6对象浏览器中的类为空)
  2. 事件未曝光

这两个问题似乎都与公开带有[ClassInterface(ClassInterfaceType. AutoDual)]属性的类有关.

我们正在使用dscom32(tlbexport/tlbregister),并且知道CA1408.

我们如何克服我们的问题(1和2),而不以类型不安全的方式重写大量VB6代码,并且不创建额外的. NET Framework 4.7.2层?

. NET 8项目文件

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

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <EnableComHosting>True</EnableComHosting>
        <PlatformTarget>x86</PlatformTarget>
    </PropertyGroup>

    <Target Name="ServerUsage" AfterTargets="Build">
        <Message Importance="High" Text="Register:%0a    regsvr32.exe &quot;$(ProjectDir)$(OutputPath)$(ComHostFileName)&quot;" />
        <Message Importance="High" Text="Unregister:%0a    regsvr32.exe /u &quot;$(ProjectDir)$(OutputPath)$(ComHostFileName)&quot;" />
    </Target>

</Project>

. NET 8代码

using System.Runtime.InteropServices;

namespace TestCOM
{
    [ComVisible(true)]
    [Guid("A5447236-9520-4596-B4C6-D40175EBDA10")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface ITestCOM
    {
        string GetString();
    }

    [ComVisible(true)]
    [Guid("3FCD4A46-F73D-495F-9DE3-85D50924ED06")]
    //[ClassInterface(ClassInterfaceType.AutoDual)]
    public class TestCOM : ITestCOM
    {
        string ITestCOM.GetString() => "Test";
    }
}

VB6代码

Sub Main()

    ' This is not working:
    ' Dim oTest As TestCOM
    ' Set oTest = New TestCOM
    '
    ' Requires ClassInterfaceType.AutoDual
    '
    ' dscom32 tlbexport "%cd%\Test.dll"
    ' -> Failed to export type library. Dual class interfaces not supported!
    
    ' This is working:
    Dim oTest As ITestCOM
    Set oTest = CreateObject("TestCOM.TestCOM")
    Debug.Print oTest.GetString()

End Sub

New code based on Seva Alekseyev

这两个问题现在都解决了.

. NET 8代码

using System;
using System.Runtime.InteropServices;

namespace TestCOM
{
    internal delegate void OnGetStringCOM(EventArgsCOM args);

    [ComVisible(true)]
    [Guid("E6BCA6A0-70F3-4218-B344-3632F638D51A")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IEventArgsCOM
    {
        string Message { get; set; }
    }

    [ComVisible(true)]
    [Guid("77414A17-1CA5-4E45-940E-F26C8F50BE3E")]
    [ClassInterface(ClassInterfaceType.None)]
    public class EventArgsCOM(string message) : EventArgs, IEventArgsCOM
    {
        public string Message { get; set; } = message;
    }

    [ComVisible(true)]
    [Guid("891E4AFB-8CD3-4611-80F6-F3AC755EF3B4")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ITestCOMEvents
    {
        [DispId(1)]
        void OnGetStringCOM(EventArgsCOM args);
    }

    [ComVisible(true)]
    [Guid("A5447236-9520-4596-B4C6-D40175EBDA10")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface ITestCOM
    {
        string GetString();
    }

    [ComVisible(true)]
    [Guid("3FCD4A46-F73D-495F-9DE3-85D50924ED06")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(ITestCOMEvents))]
    public class TestCOM : ITestCOM
    {
        private event OnGetStringCOM OnGetStringCOM;

        public string GetString()
        {
            OnGetStringCOM?.Invoke(new EventArgsCOM("test raised"));
            return "test returned";
        }
    }
}

VB6代码

Private WithEvents moTest As Test.TestCOM

Private Sub Class_Initialize()

    Set moTest = New TestCOM
    
End Sub

Public Function PrintString()

    Debug.Print moTest.GetString()
    ' test returned

End Function

Private Sub moTest_OnGetStringCOM(ByVal args As Test.IEventArgsCOM)

    Debug.Print args.Message
    ' test raised
    
End Sub

推荐答案

try 注释类(而不是接口!)用[ClassInterface(ClassInterfaceType.None)] μ你不希望. NET也为类自动生成COM接口——它会妨碍你的工作.

对于界面,try [InterfaceType(ComInterfaceType.InterfaceIsDual)]InterfaceIsIDispatch.我不记得VB6是否可以消费自定义(i. e.它不是从IDispatch接口派生出来的,但基于IDispatch的自动化一直是Visual Basic的原生操作模式.

然后重建,然后从VB项目重新建立一个引用.我不认为VB6在构建时会 Select typelib更改.

Csharp相关问答推荐

我可以将Expressc操作设置为在另一个Expressc操作完成后自动发生吗?

如何将两个查询结果组合在C#ASP.NET MHC控制器中

更改对象的旋转方向

. NET JSON属性自定义所需逻辑

MAUI查询参数单一字符串项将不起作用

Thad.Sept()vs Task.Delay().Wait()

使用Orleans进行的单元测试找不到接口的实现

在使用Audit.NET的AuditTrail实现中,如何逐月将数据摄取到AzureTableStorage?

C#使用TextFieldParser读取.csv,但无法使用";0";替换创建的列表空条目

每个http请求需要60秒,为什么?

net中从位图获取坐标和绘制折线

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

使用System.Text.Json进行序列化时发生StackOverflow异常

在C#.NET项目中启动时,如何等待提升的PowerShell进程退出?

在ASP.NET Core 8 MVC中本地化共享视图

源代码生成器:CS8795分部方法';Class1.GetS2(字符串)';必须有实现部分,因为它有可访问性修饰符?

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

解决方案:延长ABP框架和ANGING OpenIddict中的令牌生命周期

有没有更好的方法来使用LINQ获取整行的计算组

在c#中,使用Okta和Blazor时,LocalReDirect()陷入循环,出现错误&请求太多.