2016-01-15 35 views
1

我正在开发一个具有WPF GUI和非托管C++后端的桌面应用程序。 我定义API通过以下方式(C#版本,截断):注册免COM类似的互操作和线程

[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编译器等

的问题是,我无法通过iMyApp情况下,跨线程在C#中,E_NOINTERFACE异常。

我的实现是线程中立的。

如何知道,所以它停止编组我的接口跨线程,并在所有线程上使用相同的IUnknown指针?如果它很重要,我只需要支持4.5 +

+0

https://msdn.microsoft.com/en-us/library/1czb21wa.aspx –

+0

@HansPassant没有这样的选项。 Visual Studio 2015 Enterprise更新1在这里。 http://const.me/tmp/AtlSimpleObjectWizard.png – Soonts

+1

当然你会看到“Free-thread marshaler”复选框?由于您没有注册您的组件,因此CLR无法发现您的ThreadingModel。所以选择Both并让FTM负责编组。 –

回答

1

正如Hans Passant暗示的,这里的关键是CoCreateFreeThreadedMarshaler API。

添加一个私有变量CComPtr<IUnknown> m_ftm;

初始化编组:

HRESULT FinalConstruct() 
{ 
    IUnknown* pUnk = GetUnknown(); 
    return CoCreateFreeThreadedMarshaler(pUnk, &m_ftm); 
} 

过程IID_IMarshal中的QueryInterface,通过将下面的行接口映射:

COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_ftm) 

之后,C#代码将愉快地从任何线程调用这些对象。当然,你必须自己处理同步,CComAutoCriticalSection/CComCritSecLock经常帮助。

更新: MS在VS 2017中打破了我的代码,更新了答案。请参阅VS2015版本的编辑历史记录。