我们有一个项目包含很多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 ++(作为事件接收器)中实现事件逻辑的方法?
答案 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及其主要和次要版本号。
最初,我尝试将主要版本号和次要版本号留下,但这导致了类型库未注册的异常。
没有其他更改 - 例如到接收地图 - 是必要的。