扩展程序自动化中函数/属性名称冲突的解决方法

在本主题中,“object”表示 ADSI 客户端查看的对象整体。 也就是说,ADSI 及其所有扩展。

具有相同参数的相同函数名称

如果一个对象中的两个或多个双 IDispatch 接口支持同名的属性或方法,例如 Func1,则调用将根据以下标准来确定。 如果客户端拥有指向支持名为 Func1 方法的双接口之一的指针,并且自动化环境支持 vtable 访问,则 Func1 将通过 ADSI vtable 访问直接调用。

如果上述任一条件为 false,则会调用 IDispatch::GetIDsOfNamesIDispatch::Invoke 以调用 Func1

有关客户端如何向双接口添加指针的更多信息和简要说明,以及支持 vtable 访问的环境类型描述,请参阅 ADSI 扩展模型中的后期绑定与 Vtable 访问

由于所有扩展对象都会将 IDispatch 函数重定向回聚合器,因此聚合器可以控制调用哪个 Func1 函数。 规则包括:

  • 如果聚合器 (ADSI) 中有任何接口且只有一个接口支持名为 Func1 的函数,聚合器将调用其自己的 Func1
  • 否则,聚合器会按照注册表中列出的顺序逐一检查其扩展,并查找实现名为 Func1 的函数的第一个扩展。 第一个扩展中的多个双 IDispatch 接口都可能有一个名为 Func1 的函数,但可能性不大。 该扩展必须确定在自动化中应始终调用哪个 Func1

具有不同参数的相同函数名

上一节讨论了自动化中出现函数名冲突时如何解决,即函数名称与参数列表(如数量、类型和顺序)相同的函数名称冲突。 如果两个函数具有相同的名称但参数不同,该怎么办? 如果 ADSI 客户端使用 IDispatch::GetIDsOfNames 调用函数,但未使用多个名称指定参数,则 ADSI 扩展模型无法对函数进行歧义区分。 根据上文讨论的解析方案,注册表中第一个通过其接口之一支持该函数的扩展会调用其版本的该函数,调用可能会失败或产生不正确的结果。

例如:

  • Extn1(注册表中 CA 类的第一位 – 优先级更高)支持 IInterface1
  • Extn2(注册表中 CA 类下的第三位 – 优先级较低)支持 IInterface2
  • IInterface1 支持 Method1(int param1, int param2)
  • IInterface2 支持 Method1(int param1)

ADSI 客户端有一个指向 CA 类对象的 IDispatch 接口指针。 它希望调用 IInterface2::Method1。 如果客户端调用“pDispatch->GetIDsOfNames(IID_NULL, rgszNames, 1, MY_LCID, rgDispId)”,仅在 rgszNames[0] 中存储函数名 "Method1",那么调用的将是 IInterface1::Method1 而不是所需的 IInterface2::Method1 函数,并且函数会因为参数数量不同而失败。

为尽量减少这一问题,扩展开发人员可以在函数名称前加上自己的特定标识符,并避免使用同名但参数不同的函数的接口设计。

如果发生名称冲突,ADSI 客户端可以通过直接访问 vtable(如果接口是双接口)来避免此问题。 如果无法直接访问 vtable,ADSI 客户端应使用多个名称调用 IDispatch::GetIDsOfNames,并指定函数名称以及前面描述的数组 rgszNames 中的参数。

Visual Basic 5 不会调用调用具有多个名称的 IDispatch::GetIDsOfNames 函数。 也就是说,它只向 GetIDsOfNames 传递函数名称,而不传递参数。 不过,如果接口是双接口,Visual Basic 5 允许用户通过直接访问 vtable 来调用函数,而不是调用 IDispatch::GetIDsOfNames 函数。 开发人员应尽可能使用直接 vtable 访问。

有关名称冲突解决的详细信息,请参阅解决函数名称冲突的示例