2012-06-28 57 views
1

我們有一個傳統的C++ COM DLL,它在IDL中定義了一個結構。
簡化的IDL的版本包含:C#COM可見.Net程序集與傳統C++ COM DLL的結構

typedef struct 
{ 
    int num; 
} LegacyStruct; 

interface ILegacyInterface : IUnknown 
{ 
    HRESULT GetStruct([in,out] LegacyStruct* pVal); 
} 

現在,我們需要定義一個實現ILegacyInterface一個.net C#COM可見的組件。

在C#項目我們添加到傳統的COM DLL的引用,並定義實現該接口的類:

[ComVisible(true)] 
public class CSClass : ILegacyInterface 
{ 
    public void GetStruct(ref LegacyStruct pVal) 
    { 
     .... 
    } 
} 

目標是然後利用在C++ COM此COM-暴露C#組件類客戶端程序。該程序應該能夠使用傳統COM DLL和實現ILegacyInterface的新C#程序集類。

編譯時顯示以下警告:
類型庫導出器警告處理'CSClass.GetStruct(pVal)'。警告:非COM可見值類型「LegacyStruct」正在從當前正在導出的類型或其基本類型之一引用。

由於LegacyStruct不可見COM,生成的程序集的.tlb沒有公開GetStruct()方法(即,在使用oleview查看時)。
顯然,C++ COM客戶端不編譯:
錯誤C2039:「GetStruct」:不是成員「CSClass」

有一種方法,以確保LegacyStruct,其在傳統的C++中定義當在C#COM可見的.Net程序集的方法中使用時,COM DLL是否正確顯示?

+0

你應該真的使用C++/CLI包裝類來與COM通信。 – Indy9000

+0

你可以發佈該結構的非簡化IDL嗎? – tcarvin

+0

該結構的非簡化版本也非常簡單,以及... typedef struct {long {0} {long { 長msecs; 長區域; } LegacyStruct; – alexg

回答

3

爲了解決這個問題,需具備以下2項:

  1. 的傳統的COM IDL必須包括所定義的結構的uuid。這是上面提到的tcarvin。除了uuid結構標籤名稱必須與結構名稱相同。離開標籤將不夠,即,即使uuid存在。下面是新結構的定義:

    的typedef [UUID(XXX-YYY-ZZZ-AAA-BBB)]
    結構LegacyStruct
    {
    INT NUM;
    } LegacyStruct;

    沒有與結構關聯的uuid將包含其定義的副本,並在生成的.Net程序集中使用自動生成的uuid。就COM而言,這顯然是完全不同的結構。

  2. 當傳統COM DLL作爲C#項目的引用添加時,將「Embed Interop Types」屬性設置爲False非常重要。這還將確保遺留的COM DLL的定義(例如結構等)不包含在生成的.Net程序集中。

1

我意識到這並不嚴格地回答你爲什麼發生這種情況的問題,但我遇到了與tlbimp類似的問題,並且我學會了避免它。

我一般發現,.Net項目自動導入TLB的方式太嚴格了。解決此問題的一種方法是使用所有適當的ComInterface,Guid和CoClass屬性在C#文件中重新聲明IDL內容。

tlbimp +反射器也是爲這些聲明生成骨架的好方法。如果你看看tlbimp的反編譯結果,你可以看到你期望在缺少的.Net聲明上有哪些屬性,這可能會幫助你弄清楚發生了什麼。