6

我将 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"; } }
}
4

3 回答 3

6

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

DISPID 必须仅在接口内是唯一的。最好使用两个接口,每个接口都有自己的(不同的)DISPID 1 属性,即使这两个接口都是由同一个 COM 对象实现的。

但是,由于提到了 VB6,您需要记住,VB6 不喜欢在同一个 COM 对象上实现的 2+ 个调度接口,并且可能只“看到”第一个/主要的。也就是说,问题不是 DISPID 冲突(这根本不是问题),而是 VB6 无法正确处理暴露 2+ 双接口的对象这一事实。发生这种情况的原因在 MSDN 中的Multiple Dual Interfaces中进行了描述:

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

可悲的是,VB6 就是这种情况。与更高级的环境不同,它以“任何其他接口中的方法或属性”无法访问的方式查询接口。但是,分配不同的 DISPID 并无济于事。

于 2013-04-25T15:12:02.257 回答
3

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

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

如果您使用 ClassInterfaceType 作为 AutoDual 或 AutoDispatch,则会自动生成 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,它将输出以下内容(ids 是使用某种算法计算的):

Name1:1610743812 hr=0x00000000
Name2:1610743813 hr=0x00000000
于 2013-04-25T14:07:33.243 回答
0

在此处输入图像描述

DISPID 在这里必须是唯一的 8 是 DISPID .I 它重复 .它必须是唯一的

于 2021-12-15T04:49:53.750 回答