.NET 8 exposing to VB6 using COM
问题
我们有一个大型应用程序,其中有大量的GUI代码在VB6中,逻辑主要在. NET Framework 4.7.2库中.现在,我们想转移到. NET 8,并在使用COM向VB6公开库时遇到困难:
- Set oObject = New COObject不工作(VB6对象浏览器中的类为空)
- 事件未曝光
这两个问题似乎都与公开带有[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 "$(ProjectDir)$(OutputPath)$(ComHostFileName)"" />
<Message Importance="High" Text="Unregister:%0a regsvr32.exe /u "$(ProjectDir)$(OutputPath)$(ComHostFileName)"" />
</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