2013-04-25 26 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

相关问题