免注册COM类互操作和线程

时间:2016-01-15 17:16:25

标签: c# c++ windows multithreading com

我正在开发一个具有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 +

1 个答案:

答案 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版本的编辑历史记录。