Пример разрешения конфликтов имен функций
В частности, необходимо принимать во внимание следующее:
- 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.