我正在开发一个具有WPF GUI和非托管C ++后端的桌面应用程序。 我已经按照以下方式定义了API(C#版本,截断):
[Guid( "###" ), InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
interface iMyApp
{
void aMethod();
}
[DllImport( "my.dll", PreserveSig = true )]
public extern static int create( string configPath, out iMyApp a );
在后端我有
__interface __declspec( uuid( "###" ) ) iMyApp: public IUnknown
{
HRESULT __stdcall aMethod();
}
基于ATL的经典实现。
这很好用而且速度快,不需要COM注册,没有类型库,没有MIDL编译器等等。
问题是,我无法在C#中的线程之间传递iMyApp实例,引发了E_NOINTERFACE异常。
我的实现是线程中立的。
如何告诉.NET,以便它停止跨线程编组我的接口,并在所有线程上使用相同的IUnknown指针?如果重要,我只需要支持4.5 +
答案 0 :(得分:1)
正如Hans Passant所暗示,这里的关键是CoCreateFreeThreadedMarshaler API。
添加私有变量CComPtr<IUnknown> m_ftm;
初始化该编组:
HRESULT FinalConstruct()
{
IUnknown* pUnk = GetUnknown();
return CoCreateFreeThreadedMarshaler( pUnk, &m_ftm );
}
在QueryInterface中处理IID_IMarshal,方法是在接口映射中添加以下行:
COM_INTERFACE_ENTRY_AGGREGATE( IID_IMarshal, m_ftm )
之后,C#代码将很乐意从任何线程调用这些对象。当然,您必须自己处理同步,CComAutoCriticalSection / CComCritSecLock经常提供帮助。
更新: MS在VS 2017中破解了我的代码,更新了答案。请参阅VS2015版本的编辑历史记录。