我在旧的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"; } }
}
答案 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