Platform SDK: Active Directory, ADSI, and Directory Services

Example Code for Resolving Function Name Conflicts

Consider the following assumptions:

All three interfaces are dual interfaces.

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 

Note that even though IADs1 does not support Func2, an ADSI client sees one IDispatch which supports all the dual and dispatch interfaces in our model. Thus, the ADSI client can directly call Func2 using myInf1.Func2 without figuring out which interface supports Func2.

myInf1.Func2

Note that both IADs1 and IADs2 have a function called Func0, but IADs1::Func0 is invoked directly using vtable access, because the following apply to the client:

  1. It has a pointer to dual interface IADs1, which has a function called Func0, AND,
  2. Visual Basic supports direct vtable access, assuming that type information is available through the type library.

In the next example, the client has a dual interface pointer to IADs2 instead of IADs1. Therefore, IADs2::Func0 is invoked using direct vtable access.

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

Again, in the next example, both IADs1 and IADs2 have a function called Func0, but this time the client has a pointer to a dual interface, IADs0, which does not have a function called Func0. Therefore, no direct vtable access can be performed. Instead, IDispatch::GetIDsOfNames/Invoke are called to invoke Func0.

Dim myInfNone as IADs0
Set myInfNone = myInf1    ' The aggregated object which 
' supports both IADs1 & IADs2.
myInfNone.Func0 

Consider these two cases:

  1. IADs1 and IADs2 are implemented by two COM components, Ext1 and Ext2, respectively. If Ext1 comes before Ext2 in the registry, IADs1::Func0 is invoked. However, if Ext2 comes first in the registry, IADs2::Func0 is invoked.
  2. If IADs1 and IADs2 are implemented by the same extension object, Func0 is always invoked by the extension's IADsExtension::PrivateGetIDsOfNames and PrivateInvoke methods.

It's completely up to the extension developer to determine how to resolve conflicts of functions (or properties) of different dual IDispatch interfaces that have the same name in an extension. The implementation of IADsExtension::PrivateGetIDsOfNames and PrivateInvoke methods should resolve this conflict. For example, if you use IFoo::Func1 and IMoreFoo::Func1, where IFoo and IMoreFoo are dual IDispatch interfaces supported by the same extension object. The PrivateGetIDsOfNames and PrivateInvoke methods must determine which Func1 should always be called.

The same applies to conflicting DISPIDs in different dual or IDispatch interfaces.

For example, the DISPID of IFoo::Y is 2 in the file ifoo.odl (or ifoo.idl). The DISPID of IMoreFoo::X is also 2 in imorefoo.odl. IADsExtension::PrivateGetIDsOfNames must return a unique DISPID (within the extension itself) for each, instead of returning the same DISPID for both.

ADSI resolves the first problem by not supporting multiple interfaces with conflicting function or property names. It resolves the latter problem by adding a unique (within the same extension object) interface number to the unused bits of the DISPID.