Поделиться через


Пример разрешения конфликтов имен функций

В частности, необходимо принимать во внимание следующее:

  • 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 может напрямую вызывать Func2 с помощью myInf1.Func2 без разрешения какого интерфейса поддерживает Func2.

myInf1.Func2

Оба IADs1 и IADs2 имеют функцию Func0, но IADs1::Func0 вызывается напрямую с помощью vtable-доступа, так как оба из следующих действий применяются к клиенту:

  • Клиент имеет указатель на объект IADs1 с двойным интерфейсом, который имеет функцию Func0.
  • Visual Basic поддерживает прямой доступ к vtable, если тип данных доступен через библиотеку типов.

В следующем примере кода клиент имеет двойной указатель интерфейса на IADs2 вместо IADs1. Таким образом, IADs2::Func0 вызывается с помощью прямого доступа к vtable.

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

Опять же, в следующем примере кода IADs1 и IADs2 имеют функцию Func0, но здесь клиент имеет указатель на двойной интерфейс, IADs0, который не имеет функции с именем Func0. Поэтому прямой доступ к vtable не может быть выполнен. Вместо этого вызывается IDispatch::GetIDsOfNames и Invoke для вызова 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::P rivateGetIDsOfNames и PrivateInvoke.

Разработчик расширений должен определить, как разрешать конфликты функций или свойств различных двух интерфейсов IDispatch с одинаковым именем в расширении. Реализация методов IADsExtension::P rivateGetIDsOfNames и PrivateInvoke должна устранить этот конфликт. Например, если вы используете IMyInterface1::Func1 и IMyInterface2::Func1, где IMyInterface1 и IMyInterface2 являются двумя интерфейсами IDispatch, поддерживаемыми тем же объектом расширения. Методы PrivateGetIDsOfNames и PrivateInvoke должны определять, какой func1 всегда должен вызываться.

То же самое относится к конфликтующим disPID в разных двух интерфейсах или интерфейсах IDispatch.

Например, DISPID IMyInterface1::Y — 2 в файле imyinterface1.odl или imyinterface1.idl. DISPID IMyInterface2::X также 2 в iMyInterface2.odl. IADsExtension::P rivateGetIDsOfNames должен возвращать уникальный DISPID внутри самого расширения, а не возвращать один и тот же DISPID для обоих.

ADSI устраняет первую проблему, не поддерживая несколько интерфейсов с конфликтующими именами функций или свойств. Она устраняет вторую проблему путем добавления уникального объекта расширения, который находится в одном объекте расширения, номер интерфейса к неиспользуемым битам DISPID.