Как правильно запускать события COM из C # в C ++? - PullRequest
0 голосов
/ 02 мая 2018

У нас есть проект с большим количеством устаревшего кода на C ++ (с использованием ATL), VB6 и в последнее время на C #.

Недавно мы перенесли компонент из C ++ в C #, который запускает события, которые обрабатываются компонентами в C ++, VB6 и C #. Теоретически все это работает, но события запуска генерируют множество System.NotImplementedExceptions.

Я изменил код, который запускает события, чтобы он вызывал каждый обработчик событий индивидуально, чтобы исключение из одного объекта не мешало ему вызывать обработчик события в следующем объекте.

if ( GeneratedChannelChange != null )
{
  // Invoke each handler separately, so that an exception in one invokation does not prevent us calling the next one.
  foreach ( GeneratedChannelChangeEventHandler del in GeneratedChannelChange.GetInvocationList() )
  {
    try
    {
      del.Invoke ( GenChan, ChangeMask ) ;
    }
    catch  ( Exception ) {}
  }
}

Фактически исходный код C ++, сгенерированный мастером ATL, также игнорировал ошибки, возвращаемые функцией invoke.

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

Я думаю, что исключения генерируются только тогда, когда события обрабатываются в классе C ++. Это реализовано с использованием класса ATL IDispEventSimpleImpl. Я обнаружил, что IDispEventSimpleImpl не реализует функцию GetIDsOfNames . Эта функция определенно вызывается и возвращает E_NOTIMPL.

Может ли быть так, что новый код C # вызывает функцию GetIDsOfNames, но старый код C ++ этого не сделал?

Если это так, есть ли простой способ реализовать функцию GetIDsOfNames в классах, которые используют IDispEventSimpleImpl?

Если мой анализ неверен, существует ли «правильный» способ реализации логики событий в C # (как источник событий) и C ++ (как приемник событий)?

1 Ответ

0 голосов
/ 02 мая 2018

Я думаю, что я исправил проблему, заменив IDispEventSimpleImpl на IDispEventImpl .

Это более или менее вставная замена, но она требует ссылки на библиотеку типов.

Класс ATL наследует несколько базовых классов, включая класс, определенный как WorkspaceEventSink.

class ATL_NO_VTABLE CImportChannels :
  ...
  public WorkspaceEventSink,
  ...
{
   ...
}

Это было ранее определено как

typedef IDispEventSimpleImpl< 42, CImportChannels, &DIID_ICs3WorkspaceEvents>        WorkspaceEventSink ;

Я изменил определение на

typedef IDispEventImpl< 42, CImportChannels, &DIID_ICs3WorkspaceEvents, &LIBID_McAnalEventsNET, 1, 0 >        WorkspaceEventSink ;

Помимо изменения IDispEventSimpleImpl на IDispEventImpl, я добавил GUID библиотеки типов и ее основные и вспомогательные номера версий.

Первоначально я пытался оставить номера версий Major и Minor, но это привело к исключению незарегистрированной библиотеки типов.

Никаких других изменений - например, в карте стоков - не требовалось.

...