解决函数名称冲突的示例

考虑以下情况:

  • IADs0 不支持 Func0。
  • IADs1 支持 Func1 和 Func0。
  • IADs2 支持 Func2 和 Func0。

这三个接口均为双重接口。

IADs0 : IDispatch
{
    OtherFunc();
}

IADs1 : IDispatch
{
    Func0() 
    Func1();
}

IADs2 : IDispatch
{
    Func0()
    Func2();
}
Dim myInf1 as IADs1
 
myInf1.Func1  ' IADs1::Func1 is invoked using direct vtable access 
 
myInf1.Func2  ' IADs2::Func2 is invoked using GetIDsOfNames/Invoke

请注意,即使 IADs1 不支持 Func2,ADSI 客户端也会识别支持此模型中所有双重接口和调度接口的 IDispatch。 因此,ADSI 客户端可使用 myInf1.Func2 直接调用 Func2,而无需解析支持 Func2 的接口。

myInf1.Func2

IADs1 和 IADs2 均有一个名为 Func0 的函数,但 IADs1::Func0 使用 vtable 访问直接进行调用,因为以下两项均适用于客户端:

  • 客户端具有指向双重接口 IADs1 对象的指针,而该对象具有名为 Func0 的函数。
  • Visual Basic 支持直接 vtable 访问,但前提是类型库提供了该数据类型。

在下一代码示例中,客户端具有指向 IADs2 而不是 IADs1 的双重接口指针。 因此,会使用直接 vtable 访问来调用 IADs2::Func0。

Dim myInf2 as IADs2
Set myInf2 = myInf1 ' Query for pointer to IADs2 
myInf2.Func0

同样,在下一代码示例中,IADs1 和 IADs2 均有一个名为 Func0 的函数;但在此处,客户端具有指向双重接口 IADs0 的指针,而该接口没有名为 Func0 的函数。 因此,无法执行直接 vtable 访问。 相反,会调用 IDispatch::GetIDsOfNamesInvoke 来调用 Func0。

Dim myInfNone as IADs0
Set myInfNone = myInf1    ' The aggregated object that 
   ' supports IADs1 and IADs2.
myInfNone.Func0

以以下两种情况为例:

  • IADs1 和 IADs2 分别由两个 COM 组件 Ext1 和 Ext2 来实现。 如果 Ext1 比 Ext2 先加入注册表,则会调用 IADs1::Func0。 但是,如果 Ext2 先加入注册表,则会调用 IADs2::Func0。
  • 如果 IADs1 和 ADs2 由同一扩展对象实现,Func0 则始终会由该扩展的 IADsExtension::PrivateGetIDsOfNamesPrivateInvoke 方法进行调用。

扩展开发人员必须确定如何解决扩展中具有相同名称的不同双重 IDispatch 接口的函数或属性冲突。 IADsExtension::PrivateGetIDsOfNamesPrivateInvoke 方法的实现应能解决此冲突。 例如,如果使用 IMyInterface1::Func1 和 IMyInterface2::Func1,其中 IMyInterface1 和 IMyInterface2 为同一扩展对象支持的双重 IDispatch 接口。 PrivateGetIDsOfNamesPrivateInvoke 方法必须确定应始终调用哪个 Func1。

它同样适用于不同双重接口或 IDispatch 接口中互相冲突的 DISPID。

例如,IMyInterface1::Y 的 DISPID 在文件 imyinterface1.odl 或 imyinterface1.idl 中为 2。 IMyInterface2::X 的 DISPID 在 iMyInterface2.odl 中也为 2。 IADsExtension::PrivateGetIDsOfNames 必须为每个扩展自身返回唯一的 DISPID,而不是为两者返回同一 DISPID。

ADSI 会通过不支持具有冲突函数或属性名称的多个接口来解决第一个问题。 它会通过将同一扩展对象中的唯一接口号添加到 DISPID 未使用的位来解决第二个问题。