2016-01-15 38 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版本的編輯歷史記錄。