Directory API - Starting and Ending a DAPI Session

One of the ways to access MS Exchange directory objects programmatically is to use Directory API. This topic describes - how. It has a few sample code fragments to illustrate the concept.
 

Starting and Ending a DAPI Session

There are a couple of functions that you would perhaps see quite often: they are DAPIStart and DAPIEnd. The first one initializes a DAPI session and the last one terminates it. When you initialize DAPI session with DAPIStart, a handle is returned. This handle is required as a parameter to a few other DAPI functions (such as DAPIRead). The following simple code fragment (DAPIStartEnd sample) illustrates how to use this pair of functions.

uses DAPI;

procedure TForm1.Button1Click(Sender: TObject);
var
    DSession:DAPI_HANDLE;  (* Output parameter. Points to the handle of the directory operation session *)
    DAPIParms:DAPI_PARMS; (* Input parameter. Points to a DAPI_PARMS structure containing the directory interface object. *)
    pDAPIEvent:PDAPI_EVENT; (* The DAPI_EVENT structure contains information about errors that are encountered during the execution of a DAPI function *)
begin
   
DAPIParms.dwDAPISignature:=DAPI_SIGNATURE;
    DAPIParms.dwFlags := DAPI_EVENT_ALL;
 // Initialize DAPI    
  pDAPIEvent:=DAPIStart(@DSession,@DAPIParms);
    
    if Assigned(pDAPIEvent)  then 
              ShowMessage('Error')
        else
          
// We have DAPI session. We can use it here...
           begin
               ...
   
         ...
            ...
            // Terminate DAPI session
           
DAPIEnd(@DSession);
           end;
end;

DAPIStart creates a DAPI session, and DAPIEnd terminates it. If you run the above fragment in the debugger, there are a few things that you could notice:

The above code assumes that Auto Naming rules are properly defined (use Tools - Options menu of the Exchange Administrator program to see and modify current settings). Both the "Display name generation" and "Alias name generation" rules are required. If you try to execute the DAPIStart without them it'll fail with pDAPIEvent.dwDAPIError error $80001010.
 

Starting a DAPI Session on a Remote Machine

You may easily access a remote Exchange server directory. This is accomplished by specifying the directory service agent (DSA) name in the DAPI_PARMS structure before calling the DAPIStart:.

DAPIParms.pszDSAName := 'MyRemoteExchangeServer';  // Exchange server computer name

If you don't specify DSA name the DAPIStart will attempt to use the local one. If local one is not found, the first one found on the network will be used.

There are two important potential points of failure when communicating to a remote DSA.

Registry
Local registry must be properly set up. DAPI relies on two registry values under HKEY_CURRENT_USER\Software\Microsoft\Exchange\MSExchangeAdminCommon key. If this key was never set up the DAPIStart will fail with the following result:

"No Auto Naming rule was defined for %1. The default rule %2 will be used if no value for %1 is specified in the import file. An Auto Naming rule can be defined using the Options menu item in the Exchange Administrator program."

A clean machine does not have this key. You'll need to either set up the Exchange Administrator on such machine (the setup program takes care of the registry), or import the registry data (use Import Registry File / Export Registry File menu options of your regedit program).

The following two REG_SZ values are needed for DAPI: ANGAutotextFormat and DNGAutotextFormat. Set first to "%First%1Last" and second to %First %Last". Also, you'll need a REG_DWORD value named AdminLangID set up to 0x409 as described in MSDN Library article "INFO: Items Required to Use DAPI".  However, I was able to use DAPI without it. I have provided the DAPI.reg file in the Bin directory in my samples. This file contains all three entries. If you double-click it when using Windows NT Explorer, it will import them into appropriate place in the registry.

 

DLLs
Make sure you have the following DLLs in your path: Dapi.dll, Libxds.dll, Exchmem.dll. If you install Exchange Administrator on the system, they will be in your path. A clean machine, however, does not have them. You need to copy them from the machine where you have Exchange Administrator installed.

Right Security Context
You need to use correct security context for remote calls. The account used for remote access should be given appropriate permissions on Exchange server (or site). This may be done with Exchange Administrator as follows: invoke Properties dialog for the site, and on its Permissions tab add needed account. Only globally visible domain accounts may be used. If you try to use DAPI without proper security setup, it is likely to fail with the following error:

"Could not bind to the Microsoft Exchange Directory server %2. %1".

This is an insufficient security permissions error.
 

Using DAPI Calls in a Windows NT service

You may want to use DAPI in your Windows NT service application. The same two problems (registry and correct security context) apply here as well.

Registry
You need to configure the system registry as I have described above. Importing the registry file works fine. However, in case of  the Windows NT service you may run the service under different account. You will need to configure this service account for DAPI access by logging on interactively and setting up the HKEY_CURRENT_USER\Software\Microsoft\Exchange\MSExchangeAdminCommon key. Then the system will know how to obtain Exchange entries for the service even when nobody is logged on.

Right Security Context
It is possible to run a Windows NT service in the SYSTEM security context. However, the SYSTEM account is useless in this situation. If you try to access DAPI in the system context, the DAPIStart will fail with confusing "No Auto Naming rule was defined..." error. The error means DAPI can't find registry value that defines Auto Naming rule. Using the SYSTEM account for network activities is usually not a good idea. This account uses NULL credentials (no password and no domain name). It is possible to configure a remote system for such access.  However, in case of DAPI, the problem occurs earlier when DAPI can't locate necessary registry key. It will fail even when you run the service on an Exchange server computer.
 

Performance Drawback of DAPIStart

One thing that you should consider when deciding whether to use DAPI or not is the performance drawback of the DAPIStart function. As I have mentioned, it may take 10 seconds to complete. Obviously, it is not a good sign. The other thing that you may discover is the need to call DAPIStart/DAPIEnd pairs many times if you want to modify objects in different containers with DAPIWrite. This is because DAPIWrite requires proper initialization of DAPI_PARMS pszContainer member. This initialization is done during the DAPIStart call. On a good sign, only the first call to the DAPIStart is so time-consuming. Subsequent calls to DAPIEnd and DAPIStart again go much faster.

An alternative here is to use MAPI for access to directory objects. However, this requires logging on to a MAPI profile with MAPILogonEx function. This profile may not be available. For example, this may not be appropriate for writing setup programs for end users.

Compiled DELPHI 5 Application