2017-04-13 27 views
2

我有以下類:C#COM可見類型:是否需要GUID?

[ComVisible(true)] 
[Guid("F8351C66-7F0E-4E38-AE64-9A262202E230")] 
[ProgId("CarProject.CarFactory")] 
[ClassInterface(ClassInterfaceType.AutoDual)] 
public class CarFactory 
{ 
    public CarFactory() 
    {} 

    [DispId(0)] 
    public Car CreateCar(int tyres) 
    { 
     return new Car(tyres); 
    } 
} 

[ComVisible(true)] 
[Guid("83f622b9-74f4-4700-9167-52c4ce9e79aa")] 
[ClassInterface(ClassInterfaceType.AutoDual)] 
public class Car 
{ 
    [DispId(0)] 
    public int NumberOfTyres { get; private set; } 

    public Car(int tyres) 
    { 
     this.NumberOfTyres = tyres; 
    } 
} 

轎廂目的通過一種工廠創建因此COM客戶端僅使用_Car接口自動生成。請注意,沒有默認構造函數,因此無法通過COM實例化該類。

我的問題是:Guid屬性是否需要?我無法在註冊表中找到它的價值。

+0

您的工廠看起來像什麼? – stakx

+0

我不認爲這是相關的,但我已經更新了與工廠 – peval27

回答

4

不,不需要,因爲它永遠不會被使用。事實上,這是從來沒有需要和應用[Guid]是一個非常糟糕的做法。

這種聲明風格還有其他一些問題,討論它們都需要我寫一本書,這不是很實際。您可以更輕鬆地查看反編譯的類型庫,以便查看客戶端編譯器看到的內容。如果您還沒有Tlbexp.exe,請使用Visual Studio Developer命令提示符生成類型庫。運行Oleview.exe,文件>查看Typelib並選擇.tlb文件。突出顯示相關信息,您現在看到的:

importlib("mscorlib.tlb"); 

這是非常尷尬的,客戶端程序員不只是要引用添加到您的類型庫,但也在mscorlib.dll中.NET類型庫。存儲在c:\ windows \ microsoft.net \ framework \ v4.0.30319目錄中。或者v2.0.50727,舊版本。相當不直觀,並且通常不會很好地結束。請注意,在您之前的問題中,您是如何遇到麻煩的。繼續閱讀,瞭解爲什麼會發生這種情況。

[ 
    odl, 
    uuid(BD7A2C0E-E561-3EBC-8BB7-1C72EE61D5B0), 
    hidden, 
    dual, 
    nonextensible, 
    oleautomation, 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibrary171.Car")  

] 
interface _Car : IDispatch { 
    // etc.. 
} 

這是自動生成的「類接口」,您現在已經瞭解它了。這是客戶端編譯器實際用來進行調用的那個。請注意[uuid]屬性,與C#中的[Guid]屬性相同。但它有一個相當隨機的價值​​。它是自動生成的,就像界面一樣。因此,在你的聲明中使用[Guid]實際上並沒有完成任何事情。

[hidden]屬性以及接口名稱上的下劃線指示類型瀏覽器工具(如VS中的對象瀏覽器)隱藏聲明。使用OleView查看細節非常重要。否則,可以追溯到不支持接口,舊版本的Visual Basic(如VB6和VBA)以及腳本語言(如VBScript和JavaScript)的語言就是主要的例子。這些語言需要通過使界面看起來像一個類來模擬它們,這就是爲什麼你會考慮暴露類的唯一原因。

[ 
    uuid(83F622B9-74F4-4700-9167-52C4CE9E79AA), 
    version(1.0), 
    noncreatable, 
    custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "ClassLibrary171.Car") 
] 
coclass Car { 
    [default] interface _Car; 
    interface _Object; 
}; 

請注意[noncreatable]屬性。類型庫導出程序可以看到客戶端代碼無法創建Car實例,因爲它沒有默認構造函數。這反過來幫助Regasm.exe找出註冊CLSID for Car不是必需的,這就是爲什麼你無法在註冊表中找回它的原因。

並注意_Object接口。因爲每個.NET類都從System.Object派生出現。而且,_Car接口還具有Object(ToString,Equals,GetHashCode,GetType)的方法,因爲它們繼承了它們。這是你最終依賴於mscorlib.tlb的依據。他們可能可能對客戶端程序員有用,但這並不常見,你通常不希望必須記錄它們。你揭露的越少越好。


長話短說,這是因爲您使用ClassInterfaceType.AutoDual。這是一種方便,但不是很好的方式,微軟強烈反對,推薦使用ClassInterfaceType.AutoDispatch。但這隻對腳本語言有用。

您可以通過顯式聲明ICar接口來避免這一切,而不是讓類型庫導出程序爲您生成它。它需要[ComVisible(true)],並且類需要實現它。現在你可以使用ClassInterfaceType.None

現在你可以給接口一個[Guid]。但要小心這是不好的做法,COM要求接口是不可變的。一旦你暴露一個人,你永遠不會再改變它。非常重要的是,COM有一個令人討厭的DLL Hell問題,它是由機器範圍內的註冊引起的,並且您通常無法保證可以重新編譯客戶端程序。崩潰這可能會導致很難診斷。如果你不得不改變它,那麼界面需要一個新的[Guid],所以舊界面和新界面都可以共存。通過簡單地完全省略屬性來完成最簡單的事情,CLR已經自動生成它。使用[Guid]確實可以創建與舊界面聲明二進制兼容的界面,但這很難正確執行。

+0

問題感謝您的答案。你總是在這個話題上發現。我們並不擔心打破C++兼容性,因爲這不太可能從C++中使用此COM。腳本似乎是更好的候選人。相反,我沒有考慮到你對mscorlib的引用所說的話! – peval27

相關問題