События COM от C # до VB6 («объект или класс не поддерживает набор событий»), но разные

Мне известен вопрос 10-летней давности с тем же названием, что и этот, но я дважды проверил и не ошибочно использую имя делегата. Это другой вопрос.

Здесь, на работе, у нас есть старое приложение VB6, которое мне нужно научить новым трюкам. Первое, что мне нужно было сделать, это вызвать методы из .Net COM-видимой DLL, написанной на C #. У меня это работает. Теперь мне нужно, чтобы он обрабатывал входящие события уведомления о ходе выполнения из той же библиотеки DLL. Вчера я задал аналогичный вопрос, в котором IDE VB6 даже не видела, что у 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

person davecove    schedule 13.01.2020    source источник
comment
Отвечает ли это на ваш вопрос? Предоставление событий .NET для COM?   -  person GSerg    schedule 13.01.2020
comment
@GSerg Нет, потому что это похоже на то, что у меня уже есть. Он включает в себя отображение асинхронных задач через интерфейс, что мне нужно сделать дальше, так что спасибо за это. :)   -  person davecove    schedule 13.01.2020
comment
Вам не хватает [ClassInterface(ClassInterfaceType.None)], но я не уверен, имеет ли это значение.   -  person GSerg    schedule 13.01.2020
comment
Не похоже. Я пробовал это раньше (и просто попробовал снова), и это не помогло.   -  person davecove    schedule 13.01.2020
comment
Какая именно строка выдает ошибку?   -  person StayOnTarget    schedule 14.01.2020


Ответы (2)


Надеюсь, это может помочь - вот минимальная реализация ваших требований на 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, добавления элемента COM-класса, переименованного в NewTricks. Затем добавили объявление события, суб-объявление и код; также добавлены операторы Option. Построил проект.

Это было успешно использовано из этого кода VB6. Нажатие на кнопку привело к появлению сообщения «Событие запущено» в непосредственном окне. Это было успешным с использованием как New, так и CreateObject методов создания ссылки на 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

Вот соответствующий код C # для кода VB.net, преобразованный напрямую с помощью https://converter.telerik.com/

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 #.

person MarkL    schedule 14.01.2020

Если вы используете CreateObject, он создает объект типа Object, который я считаю. Вы должны создать объект, просто используя New:

Set _tricky = New NewTricksDLL.NewTricks

Поскольку вы объявили переменную как WithEvents, вы не можете просто объявить ее с помощью As New NewTricksDLL.NewTricks, который, как я полагаю, вы, вероятно, пробовали.

person Étienne Laneville    schedule 14.01.2020
comment
Это определенно стоит попробовать, но я не уверен, что это проблема. Поскольку _tricky определен с правильным типом, я думаю, что результат CreateObject() следует использовать правильно. То есть, если он действительно не возвращает объект ожидаемого типа. - person StayOnTarget; 14.01.2020
comment
New и CreateObject оба приводят к 'Object or class does not support the set of events'. Опять же, ObjectBrowser показывает события в этой сборке. - person davecove; 14.01.2020