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

时间:2013-04-25 13:29:59

标签: c# com

我在旧的VB6应用程序中使用COM。

我将代码更改为在接口中使用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 个答案:

答案 0 :(得分:5)

  

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

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

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

  

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

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

答案 1 :(得分:2)

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

编辑:事实上,正如汉斯在评论中指出的那样,在仔细考虑之后,这个问题就完全无关紧要了。因为您将ClassInterfaceType定义为None,这意味着.NET只会使第一个接口IMyInterface1可用于调用(默认情况下,您可以使用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