C# 到 VB6 的 COM 事件(“对象或类不支持事件集合”),但是不同

3

我知道有一个与这个问题标题相同的10年前的问题,但我已经仔细检查过了,我没有错误地使用委托名称。这是一个不同的问题。

在我们公司,我们有一个老旧的VB6应用程序,我需要教它一些新技巧。我必须做的第一件事是让它调用由C#编写的.NET可见COM DLL中的方法。我已经解决了这个问题。现在我需要让它处理来自同一DLL的进度通知事件。昨天我问了一个类似的问题,其中VB6 IDE甚至没有看到DLL提供的事件。那个问题已经通过正确装饰C#接口和类来解决了。

首先,是这段C#代码:

namespace NewTricksDLL
{
    [ComVisible(true)]
    [Guid("16fb3de9-3ffd-4efa-ab9b-0f4117259c75")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ITransfer
    {
        [DispId(2)]
        string SendAnEvent();
    }

    [ComVisible(true)]
    [Guid("16fb3de9-3ffd-4efa-ab9b-0f4117259c74")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IManagedEventsToCOM
    {
        [DispId(2)]
        void NotificationEvent();

    }

    [ComVisible(true)]
    [Guid("dcf177ab-24a7-4145-b7cf-fa06e892ef21")]
    [ComSourceInterfaces(typeof(IManagedEventsToCOM))]
    [ProgId("ADUTransferCS.NewTricks")]
    public class NewTricks : ITransfer
    {
        public delegate void NotificationEventHandler();
        public event NotificationEventHandler NotifificationEvent;

        public string SendAnEvent()
        {
            if (NotifificationEvent != null)
                NotifificationEvent();           
        }
    }
}

现在我尝试在VB6中使用它。请注意,_tricky_NotificationEvent事件处理程序是由IDE通过从左侧下拉菜单选择_tricky和从右侧下拉菜单选择NotificationEvent生成的,因此我知道该事件对于VB6 IDE是可见的。

Option Explicit

Public WithEvents _tricky As NewTricksDLL.NewTricks

Private Sub Command1_Click()
    ' The next line fails with 'Object or class does not support the set of events'
    Set _tricky = CreateObject("NewTricksDLL.NewTricks")
    ' Execution never makes to the next line
    _tricky.SendAnEvent()

End Sub

Private Sub _tricky_NotificationEvent()
    ' This handler was auto generated by the IDE
End Sub

这个回答解决了你的问题吗?将.NET事件暴露给COM? - GSerg
@GSerg 不用了,因为它看起来就像我已经拥有的。不过它确实包括通过接口公开异步任务,这是我需要做的下一步,所以谢谢你。 :) - davecove
你虽然缺少了[ClassInterface(ClassInterfaceType.None)],但我不确定它是否重要。 - GSerg
似乎没有用。我之前尝试过(现在又试了一次),但并没有帮助。 - davecove
你出现错误的确切代码行是哪一行? - StayOnTarget
2个回答

1

希望这可以帮助 - 这是一个最小的VB.net实现,符合您的要求:COM接口可被VB6使用,一个事件,一个方法。

Option Explicit On
Option Strict On

<ComClass(newTricks.ClassId, newTricks.InterfaceId, newTricks.EventsId)>
Public Class newTricks

#Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "386d540d-f8b8-46e1-939d-7b69dd5eff0a"
    Public Const InterfaceId As String = "78b4036e-86a0-4671-997d-da5a33bf026f"
    Public Const EventsId As String = "7b0fa5b5-b45e-4db2-9282-c06e09852161"
#End Region

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject.
    Public Sub New()
        MyBase.New()
    End Sub

    Public Event NotificationEvent()

    Public Sub SendAnEvent()
        RaiseEvent NotificationEvent()
    End Sub
End Class

这是通过创建一个新项目(Windows类库)创建的,从项目中删除自动创建的Class1.vb文件,添加一个重命名为NewTricks的COM类项。然后添加事件声明、子声明和代码;还添加了Option语句。构建项目。
此方法已成功用于VB6代码。单击按钮会在立即窗口中写入“事件已触发”。使用NewCreateObject方法都可以成功创建对newTricks的引用。
Option Explicit

Private WithEvents oTricks As NewTricksDll.newTricks

Private Sub Command1_Click()

  Set oTricks = New NewTricksDll.newTricks
  'Set oTricks = CreateObject("NewTricksDll.newTricks")

  oTricks.SendAnEvent

End Sub

Private Sub oTricks_NotificationEvent()
  Debug.Print "Event fired"
End Sub

以下是VB.net代码通过https://converter.telerik.com/转换成的C#代码:

using Microsoft.VisualBasic;

[ComClass(newTricks.ClassId, newTricks.InterfaceId, newTricks.EventsId)]
public class newTricks
{

    // These  GUIDs provide the COM identity for this class 
    // and its COM interfaces. If you change them, existing 
    // clients will no longer be able to access the class.
    public const string ClassId = "386d540d-f8b8-46e1-939d-7b69dd5eff0a";
    public const string InterfaceId = "78b4036e-86a0-4671-997d-da5a33bf026f";
    public const string EventsId = "7b0fa5b5-b45e-4db2-9282-c06e09852161";

    // A creatable COM class must have a Public Sub New() 
    // with no parameters, otherwise, the class will not be 
    // registered in the COM registry and cannot be created 
    // via CreateObject.
    public newTricks() : base()
    {
    }

    public event NotificationEventEventHandler NotificationEvent;

    public delegate void NotificationEventEventHandler();

    public void SendAnEvent()
    {
        NotificationEvent?.Invoke();
    }
}

我还没有尝试过这段C#代码。


0
如果您使用CreateObject,它会创建一个类型为Object的对象。您应该通过使用New来创建对象:
Set _tricky = New NewTricksDLL.NewTricks

由于您将变量声明为 WithEvents,因此您不能仅使用 As New NewTricksDLL.NewTricks 进行声明,我想您可能已经尝试过了。


这绝对值得一试,但我不确定它是否是问题所在。由于 _tricky 已经定义为正确的类型,我认为 CreateObject() 的结果应该被正确使用。除非它确实没有返回预期类型的对象。 - StayOnTarget
1
NewCreateObject都会导致“对象或类不支持事件集”错误。同样,ObjectBrowser在该程序集中显示了这些事件。 - davecove

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接