Przykład rozwiązywania konfliktów nazw funkcji
Rozważ następujące kwestie:
- Usługa IADs0 nie obsługuje platformy Func0.
- Usługa IADs1 obsługuje platformy Func1 i Func0.
- Usługa IADs2 obsługuje platformy Func2 i Func0.
Wszystkie trzy interfejsy to dwa interfejsy.
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
Należy pamiętać, że mimo że usługa IADs1 nie obsługuje platformy Func2, klient ADSI rozpoznaje jeden IDispatch, który obsługuje wszystkie interfejsy podwójne i dyspozytora w modelu. W związku z tym klient ADSI może bezpośrednio wywoływać func2 przy użyciu myInf1.Func2 bez rozpoznawania interfejsu obsługującego func2.
myInf1.Func2
Zarówno IADs1, jak i IADs2 mają funkcję o nazwie Func0, ale IADs1::Func0 jest wywoływana bezpośrednio przy użyciu dostępu vtable, ponieważ oba następujące elementy mają zastosowanie do klienta:
- Klient ma wskaźnik do obiektu IADs1 z podwójnym interfejsem, który ma funkcję o nazwie Func0.
- Język Visual Basic obsługuje bezpośredni dostęp do tabel wirtualnych, przy założeniu, że typ danych jest dostępny za pośrednictwem biblioteki typów.
W następnym przykładzie kodu klient ma podwójny wskaźnik interfejsu do identyfikatorów IADs2 zamiast IADs1. W związku z tym usługa IADs2::Func0 jest wywoływana przy użyciu bezpośredniego dostępu do tabel wirtualnych.
Dim myInf2 as IADs2
Set myInf2 = myInf1 ' Query for pointer to IADs2
myInf2.Func0
Ponownie, w następnym przykładzie kodu, zarówno IADs1, jak i IADs2 mają funkcję o nazwie Func0, ale tutaj klient ma wskaźnik do podwójnego interfejsu IADs0, który nie ma funkcji o nazwie Func0. W związku z tym nie można wykonać bezpośredniego dostępu do tabeli wirtualnej. Zamiast tego wywoływane są IDispatch::GetIDsOfNames i Invoke w celu wywołania funkcji Func0.
Dim myInfNone as IADs0
Set myInfNone = myInf1 ' The aggregated object that
' supports IADs1 and IADs2.
myInfNone.Func0
Rozważ następujące dwa przypadki:
- IADs1 i IADs2 są implementowane przez dwa składniki COM, Ext1 i Ext2, odpowiednio. Jeśli ext1 występuje przed Ext2 w rejestrze, wywołano identyfikatory IADs1::Func0. Jeśli jednak ext2 pojawia się jako pierwszy w rejestrze, wywołana jest funkcja IADs2::Func0.
- Jeśli identyfikatory IAD1 i ADs2 są implementowane przez ten sam obiekt rozszerzenia, func0 jest zawsze wywoływany przez metody IADsExtension::P rivateGetIDsOfNames i PrivateInvoke metod.
Deweloper rozszerzenia musi określić, jak rozwiązywać konflikty funkcji lub właściwości różnych podwójnych IDispatch interfejsów o tej samej nazwie w rozszerzeniu. Implementacja IADsExtension::P rivateGetIDsOfNames i metody PrivateInvoke powinny rozwiązać ten konflikt. Jeśli na przykład używasz interfejsów IMyInterface1::Func1 i IMyInterface2::Func1, gdzie IMyInterface1 i IMyInterface2 są dwoma interfejsami IDispatch obsługiwanymi przez ten sam obiekt rozszerzenia. Metody PrivateGetIDsOfNames i PrivateInvoke muszą określić, które metody Func1 powinny być zawsze wywoływane.
To samo dotyczy konfliktowych identyfikatorów DISPID w różnych interfejsach podwójnej lub IDispatch.
Na przykład identyfikator DISPID elementu IMyInterface1::Y to 2 w pliku imyinterface1.odl lub imyinterface1.idl. Identyfikator DISPID interfejsu IMyInterface2::X jest również 2 w pliku iMyInterface2.odl. IADsExtension::P rivateGetIDsOfNames musi zwrócić unikatowy identyfikator DISPID w obrębie samego rozszerzenia, dla każdego, zamiast zwracać ten sam identyfikator DISPID dla obu.
ADSI rozwiązuje pierwszy problem, nie obsługując wielu interfejsów z nazwami funkcji lub właściwości powodujące konflikt. Rozwiązuje to drugi problem, dodając unikatowy, który znajduje się w tym samym obiekcie rozszerzenia, numer interfejsu do nieużywanych bitów identyfikatora DISPID.