Early Binding Support
The following code example presents a scenario with early binding support in place.
Dim x as IADsUser
Dim y as IADsExt1
Dim z as IADsExt2
Set x = GetObject("LDAP://CN=JeffSmith, OU=Sales,
DC=Fabrikam,DC=COM")
x.SetPassword("newPassword")
Set y = x
y.MyNewMethod( "\\srv\public")
y.MyProperty = "Hello World"
Set z = y
z.OtherMethod()
z.OtherProperty = 4362
Debug.Print x.LastName
Set z = GetObject("LDAP://CN=Jeff,OU=Engr,
DC=Fabrikam,DC=COM")
z.OtherProperty = 5323
In this code example, two extension components extend a user object. Each extension publishes its own interface. Each extension does not recognize the other extension interface; only ADSI recognizes the existence of both extensions. Each extension delegates its IUnknown to ADSI. ADSI acts as an aggregator for both extensions, and any other future extensions. Querying an interface from any extension, or from ADSI, yields the same consistent result.
The following procedure describes how to create an extension.
Step 1: Add Aggregation to Your Component
Follow the COM specification for adding aggregation to your component. In summary, you must accept the pUnknown requests to your component during CreateInstance, and delegate the pUnknown to the aggregator's IUnknown if the component is aggregated.
Step 2: Register Your Extension
Now you must decide which directory class to extend. You cannot use the same interfaces to accomplish this that you would use for an ADSI interface, for example, IADsUser, IADsComputer. Directory objects are persisted in the directory, while your extension and ADSI are running on the client computer. Directory object examples are user, computer, printQueue, serviceConnectionPoint, and nTDSService. You can add a new class in Active Directory and create a new extension for this new class as well.
You use registry keys to associate a directory class name with the ADSI extension components. The following figure represents the existing registry layout, as a well as new keys.
- A new key, called Extensions, contains a list of keys, each of which represents a class in the directory. Each class, for example, user, printQueue, or computer, maintains a list of subkeys.
- Each subkey contains the CLSID of the ADSI extension component.
- Each CLSID subkey contains a string entry that allows multiple values. You should only list the interfaces that participate in the aggregation.
Note
Extension objects are still required to register standard COM keys.
HKEY_LOCAL_MACHINE
Software
Microsoft
ADS
Providers
LDAP
Extensions
ClassNameA
CLSID of ExtensionA1
Interfaces = List of interfaces
CLSID of ExtensionA2
Interfaces = List of interfaces
ClassNameB
CLSID of ExtensionB1
Interfaces = List of interfaces
CLSID of ExtensionB2
Interfaces = List of interfaces
Example
HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
ADs
Providers
LDAP
Extensions
printQueue
{9f37f39c-6f49-11d1-8c18-00c04fd8d503}
Interfaces = {466841B0-E531-11d1-8718-00C04FD44407}
{466841B1-E531-11d1-8718-00C04FD44407}
The list of interfaces from Extension1 can be different from that of Extension2. The object, when active, supports the interfaces of the aggregator (ADSI) and all the interfaces provided by the aggregate's Extension1 and Extension2. Resolution of conflicting interfaces (the same interface supported by both the aggregator and the aggregates or by multiple aggregates) is determined by priorities of the extensions.
You can also associate your CLSID extension with multiple object class names. For example, your extension can extend both the user and contact objects.
Note
Extension behavior is added on a per-object class, not on a per-object instance.
As a best practice, register your extensions, as you would any other COM components, with a call to the DllRegisterSvr function. Also provide a facility to unregister your extension with the DllUnregisterServer function.
The following code example shows how to register an extension.
/////
// Register the class.
///////////////////////
hr = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\Microsoft\\ADs\\Providers\\LDAP\\Extensions\\User\\{E1E3EDF8-48D1-11D2-B22B-0000F87A6B50}"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&dwDisposition );
///////////////////////////
// Register the Interface.
///////////////////////////
const TCHAR szIf[] = _T("{E1E3EDF7-48D1-11D2-B22B-0000F87A6B50}");
hr = RegSetValueEx( hKey, _T("Interfaces"), 0, REG_BINARY, (const BYTE *) szIf, sizeof(szIf) );
RegCloseKey(hKey);
return S_OK;
}