Directory Services |
Here is a scenario with early binding support in place. The following code is an example.
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 example, two extension components extend a user object. Each extension publishes its own interface. Each extension is not aware of the other extension interface; only ADSI is aware of 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.
Look at the steps required to make an extension.
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.
Now you must decide which directory class you want 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 machine. 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.
Note Extension objects are still required to register standard COM keys.
HKLM |__Software |___Microsoft |____ADS
|__Providers
|__LDAP <continue from above>
LDAP
|__Extensions
|___<ClassNameA>
|____<CLSID of ExtensionA1>
Interfaces(REG_BINARY) {List of interfaces)
|____<CLSID of ExtensionA2>
Interfaces(REG_BINARY) {List #1 of interfaces)
|____ <ClassNameB>
|____<CLSID of ExtensionB1>
Interfaces(REG_BINARY) {List of interfaces)
|____<CLSID of ExtensionB2>
Interfaces(REG_BINARY) {List #1 of interfaces)
[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.
It is best to register your extensions, as you would any other COM components, with a call to the DllRegisterSvr function. You should also provide a facility to unregister your extension with the DllUnregisterServer function.
The following 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; }