从COM#到C ++触发COM事件的正确方法是什么

时间:2018-05-02 10:36:01

标签: c# c++ com com-interop atl

我们有一个项目包含很多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 ) {}
  }
}

实际上,ATL向导生成的原始C ++代码也忽略了调用函数返回的错误。

这似乎工作正常,但我对它产生的大量异常感到不满意。在调试器中运行时,这也会破坏性能。

我认为只有在C ++类中处理事件时才会抛出异常。这是使用ATL类IDispEventSimpleImpl实现的。我发现的是, IDispEventSimpleImpl 没有实现函数 GetIDsOfNames 。这个函数肯定被调用,它返回E_NOTIMPL。

可能是,新的C#代码正在调用函数GetIDsOfNames,但旧的C ++代码没有?

如果是这种情况,有没有简单的方法在使用IDispEventSimpleImpl的类中实现GetIDsOfNames函数?

如果我的分析错了,是否有正确的'在C#(作为事件源)和C ++(作为事件接收器)中实现事件逻辑的方法?

1 个答案:

答案 0 :(得分:0)

我认为我已经解决了这个问题,将 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及其主要和次要版本号。

最初,我尝试将主要版本号和次要版本号留下,但这导致了类型库未注册的异常。

没有其他更改 - 例如到接收地图 - 是必要的。