2013-04-25 27 views
5

我使用COM與舊的VB6應用程序。DispID在接口上必須是唯一的嗎?

我改變了我的代碼以使用DISPID的接口,它似乎工作比使用[ClassInterface(ClassInterfaceType.AutoDual)]更好。

但是,它允許在每個接口從DISPID(1)計數開始,即使當類使用兩個接口?

它這樣工作穩定嗎?或者我錯過了某些東西?

[ComVisible(true)] 
[Guid("9E1125A6-...")] 
public interface IMyInterface1 
{ 
    [DispId(1)] 
    string Name1 { get; } 
} 

[ComVisible(true)] 
[Guid("123425A6-...")] 
public interface IMyInterface2 
{ 
    [DispId(1)] 
    string Name2 { get; } 
} 

[ComVisible(true)] 
[ClassInterface(ClassInterfaceType.None)] 
class MyClass : IMyInterface1, IMyInterface2 
{ 
    public string Name1 { get { return "Name1"; } } 
    public string Name2 { get { return "Name2"; } } 
} 
+2

您列出的第一個界面是VB6在延遲綁定時可以看到的唯一界面。它將是標記爲[默認]界面的界面。所以不是一個真正的問題,因爲其他接口無法使用。儘管這可能是一個真正的問題;) – 2013-04-25 20:11:32

回答

5

是否允許從每個從DispID(1)計數的接口開始,即使一個類使用兩個接口?

的DISPID必須是唯一的接口中是唯一的。即使兩個接口都由同一個COM對象實現,您也可以使用兩個接口,每個接口都有自己的(不同的)DISPID 1屬性。

由於VB6被提及,但是,你需要記住,VB6不會喜歡2+同COM對象上實現調度接口,並且可能是「看」只有第一個/主之一。也就是說,問題不在於DISPID碰撞(根本不是問題),而是VB6無法正確使用公開2+ 2+雙接口的對象。這是爲什麼在MSDN上描述Multiple Dual Interfaces發生的原因是:

因爲只有一個IDispatch接口暴露出來,只能通過IDispatch接口訪問對象的客戶端將無法訪問任何方法或屬性其他界面。

不幸的是,這是VB6的情況。與更高級的環境不同,它以「任何其他接口中的方法或屬性」無法訪問的方式查詢接口。儘管分配不同的DISPID不會對此有所幫助。

2

有每個COM對象只有一個IDispatch實現,所以如果你想要一個調用,如IDispatch::Invoke成功,你需要有每個COM對象唯一的DISPID。

編輯:事實上,更多地考慮之後,這個問題是相當無關緊要,因爲漢斯他的評論指出。因爲您將ClassInterfaceType定義爲None,這意味着.NET只會使第一個接口IMyInterface1的dispids可用(默認情況下,但您可以使用ComDefaultInterfaceAttribute Class屬性配置默認接口)。

如果你使用ClassInterfaceType作爲AutoDual或AutoDispatch,dispid的將被自動生成的,並手動定義的將不會被使用。

.NET沒有合併或合併的接口,以及一個事實,即dispid的是不同的,因此沒有在這個「.NET暴露爲COM」情況很重要,因爲只有一組的DISPID被使用(默認界面)。請注意,如果您在同一個類中定義兩次相同的DISPID集,它將編譯得很好,但是regasm會抱怨而忽略重複的。

這裏是一個小的C++程序,證實了這一切:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    CoInitialize(NULL); 
    IDispatch *pDispatch; 
    CoCreateInstance(__uuidof(MyClass), NULL, CLSCTX_ALL, IID_IDispatch, (void**)&pDispatch); 
    DISPID dispid; 
    LPOLESTR name1 = L"Name1"; 
    LPOLESTR name2 = L"Name2"; 
    HRESULT hr; 
    hr = pDispatch->GetIDsOfNames(IID_NULL, &name1, 1, 0, &dispid); 
    printf("Name1:%i hr=0x%08X\n", dispid, hr); 
    hr = pDispatch->GetIDsOfNames(IID_NULL, &name2, 1, 0, &dispid); 
    printf("Name2:%i hr=0x%08X\n", dispid, hr); 
    pDispatch->Release(); 
    CoUninitialize(); 
    return 0; 
} 

它會輸出這樣的:

Name1:1 hr=0x00000000 (S_OK) 
Name2:-1 hr=0x80020006 (DISP_E_UNKNOWNNAME) 

它你AutoDispatch或AutoDual變化,它將輸出這個(IDS計算使用一些算法):

Name1:1610743812 hr=0x00000000 
Name2:1610743813 hr=0x00000000 
+0

每個COM對象沒有一個IDispatch的限制。那麼,IDispatch可以是一個,但是對象實現了從IDispatch派生**的接口,並且它們的數量不受限制(當然DISPID被分配給這些派生接口的方法,而不是IDispacth)。 – 2013-04-25 15:14:32

+0

我不認爲我說什麼與你說的相反。但是由於同一個COM對象總是返回相同的IDispatch指針,所以在使用IDispatch接口時,我很難看到如何使用具有相同DISPID的兩個方法。沒有什麼物理實施該規則。如果它有效(並且我從來沒有說OP的代碼不會按原樣工作,並且同一個Dispid聲明瞭兩次),這是因爲代碼最終沒有使用IDispatch接口。 – 2013-04-25 15:51:53

+0

問題是很少有應用程序查詢IDispatch。相反,它們直接查詢IDispatch派生的接口(例如,它們是通過類型庫發現的),所以不存在多個IDispatch實現的問題,並且它們都是完全可用的。不只是通過VB6,但它更像是一個例外(不尋常的限制)。 – 2013-04-25 16:25:18

相關問題