DispID在接口之间必须是唯一的吗?

我使用COM与旧的VB6应用程序。

我更改了我的代码以在接口中使用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"; } } } 

是否允许从DispID(1)计数的每个接口开始,即使一个类使用两个接口?

DISPID只能在界面中唯一。 你最好使用两个接口,每个接口都有自己的(不同的)DISPID 1属性,即使两个接口都是由同一个COM对象实现的。

但是,由于提到了VB6,你需要记住VB6不会喜欢在同一个COM对象上实现的2个以上的调度接口,并且可能只“看到”第一个/主要的。 也就是说,问题不是DISPID冲突(这根本不是问题),而是VB6无法正常使用暴露2+双接口的对象。 在多个双接口的 MSDN中描述的原因:

由于只公开一个IDispatch接口,因此只能通过IDispatch接口访问对象的客户端将无法访问任何其他接口中的方法或属性。

遗憾的是,这是VB6的情况。 与更高级的环境不同,它以“任何其他接口中的方法或属性”不可访问的方式查询接口。 虽然分配不同的DISPID不会有帮助。

每个COM对象只有一个IDispatch实现,因此如果您希望IDispatch :: Invoke等调用成功,则每个COM对象都需要具有唯一的DISPID。

编辑:事实上,正如汉斯在评论中指出的那样,在仔细考虑之后,这个问题就变得无关紧要了。 因为您将ClassInterfaceType定义为None,这意味着.NET只会使第一个接口IMyInterface1 dispids可用(默认情况下,您可以使用ComDefaultInterfaceAttribute Class属性配置默认接口)。

如果您使用ClassInterfaceType作为AutoDual或AutoDispatch,将自动生成DISPID,并且不会使用手动定义的DISPID。

.NET不会合并或合并接口,因此,在这个“.NET公开为COM”的情况下,dispid不同的事实并不重要,因为只使用了一组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,它将输出此信息(ID使用某种算法计算):

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