2009-10-06 29 views
3

我一直在與VStudio,谷歌和其他各種工具和網站作鬥爭整天,發現沒有解決方案 - 幫助!絕對COM混亂 - 與早期綁定的C#互操作

我有兩個COM接口(純COM,沒有ATL):

IMyClassFactory和IMyClass與相應實現

我想從C#,但沒有與REGSVR32註冊COM服務器使用它們。 我用CoRegisterClassObject公開類工廠,我可以用非託管代碼成功創建帶有CoCreateInstance的IMyClass對象。

所以C#互操作...

我創建了TLBIMP myComServer.tlb一個.NET包裝並加載它作爲我的C#客戶端的參考。

然後,當我嘗試創建IMyClass的實例,我得到:

An unhandled exception of type 'System.InvalidCastException' occurred in COMTestClient.exe 

Additional information: Unable to cast COM object of type 'MyComServerLib.MyClass' to interface type 'MyComServerLib.IMyClass'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{9F8CBFDC-8117-4B9F-9BDC-12D2E6A92A06}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)). 

現在,我已經添加的痕跡到的QueryInterface,當我返回E_NOINTERFACE的唯一情況是,當它的任何請求與統帥相關的接口或用於IManagedObject。

我該如何解決這個問題?

編輯:我的IDL文件:

import "unknwn.idl"; 

[ 
    object, 
    uuid(...), 
    nonextensible, 
    pointer_default(unique) 
] 
interface IMyClass : IUnknown 
{ 
    HRESULT(SetFirstNumber)(long nX1); 

    HRESULT(SetSecondNumber)(long nX2); 

    HRESULT(DoTheAddition)([out,retval] long *pBuffer); 
}; 

[ 
    uuid(...) 
] 
library MyLib 
{ 
    importlib("stdole2.tlb"); 

    [ 
     uuid(...) 
    ] 
    coclass IMyClassImpl 
    { 
     [default] interface IMyClass; 
    }; 
} 

回答

4

您需要可以讓你的界面將被編組(即,通過在.idl文件將其標記爲不是「本地」,使其在結束了類型庫和代理/存根),或者如果你這樣做的話聚合自由線程編組器。

要聚集FTM,我做了這樣的事情:

#define DECLARE_FTM() \ 
protected: CComPtr<IUnknown> _m_Marshal; \ 
DECLARE_GET_CONTROLLING_UNKNOWN() \ 
public: HRESULT FinalConstruct() \ 
{ return CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&_m_Marshal); } 

#define COM_INTERFACE_ENTRY_FTM() COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal,_m_Marshal.p) 

然後,在你的COM地圖:

BEGIN_COM_MAP(Blah) 
    COM_INTERFACE_ENTRY(IBlah) 
    COM_INTERFACE_ENTRY_FTM() 
END_COM_MAP() 
DECLARE_FTM() 

我注意到,您不使用ATL之類 - 你需要修改這個,以便在查詢IMarshal時QueryInterface實現返回FTM指針。

請注意,彙總FTM不是真的可以輕易完成的 - 它會產生許多不安全的假設,這些假設並非總是有效。例如,你的類不能使用任何本身不是自由線程的接口。

另一種選擇基本上是@ [Franci Penov]說的,你需要確保你的界面能夠被編組。我瞭解它的方式,有一個標準的編組器可以編組類型庫中的任何接口,或者你(這是midl編譯器自動或多或少地執行它)可以創建代理/存根dll(或合併代碼爲代理/存根到你自己的dll),它可以爲你編組它。

這篇文章更詳細的here describes the process of building and registering the proxy/stub

+0

您可以添加更多關於如何執行任一解決方案的信息嗎?我將用我的IDL文件編輯我的原始文章。謝謝 – georgiosd 2009-10-06 23:02:06

+0

我已經添加了一些更多的細節 – 2009-10-06 23:57:56

+0

COM對象的引用計數實現是否也需要線程安全,使用互鎖操作?如果CLR將COM對象視爲自由線程,它將從終結器線程調用它。 – 2009-10-07 06:36:01

1
  1. 將您的界面移動到庫部分。這將在類型庫中得到它的定義。
  2. 將您的界面標記爲oleautomation。這將標記爲可以通過使用標準編組器和typelib信息編組的接口,而不是由midl編譯器生成的代理/存根。 (注意:雖然oleautomation確實來自舊的OLE世界,但它不需要您的接口從IDispatch派生)