Using IDirectorySearch for Querying

In addition to the search capabilities supported by the ADSI OLE DB provider, ADSI supplies the IDirectorySearch interface to query directly directory services for non-Automation clients. IDirectorySearch requires almost the same search information as the methods of the OLE DB interfaces, but reduces the programming overhead. Use IDirectorySearch when you just want to specify a query and get the results back without any of the richer navigation features supplied when using OLE DB queries.

When implemented by a provider, IDirectorySearch is supported on every ADSI object. For information on which providers support this interface, see ADSI System Providers.

Use IDirectorySearch::SetSearchPreference to set the preferred settings for your query. Once your preferences are created, use ExecuteSearch to initiate the query. Query results are exposed in the form of a table. Each row is one entry of the result. Each column within the row represents an attribute or property. The following figure shows a simplified representation of how the query process works.

Use GetNextRow to advance the search handle shown in the preceding figure row by row, and GetNextColumnName with GetColumn to retrieve results from the columns. With each row you step through the columns of interest looking for the attributes that match. This process continues until there are no more rowsets in the query results.

The following ADSI example shows a simple command-prompt program that uses the IDirectorySearch interface to query a directory service. This sample has been edited, primarily by removing error checking, to simplify the flow. The complete example code is included in the ADSI SDK in the samples/activeds/sampapp/cxx/dssrch directory.


Usage: dssrch /b <baseObject> /f <search_filter> [/f <attrlist>] [/p <preference>=value>]  [/u <UserName> <Password>] [/t <flagName>=<value> 
 
   where:
   baseObject     = ADsPath of the base of the search
   search_filter  = search filter string in LDAP format
   attrlist       = list of the attributes to display
   preference could be one of:
   Asynchronous, AttrTypesOnly, DerefAliases, SizeLimit, TimeLimit,
   TimeOut, PageSize, SearchScope
   flagName could be one of:
   SecureAuth or UseEncrypt
   value is yes/no for a Boolean and the respective integer for integers
   scope is one of "Base", "OneLevel", or "Subtree"
 
For Example: dssrch /b NDS://ntmarst/ms /f "(object Class=Group)"  /a  "ADsPath, name, description" /p searchScope=onelevel
 
//------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1997.
//
//-------------------------------------------------------------------
#define INC_OLE2
#include <windows.h>
#include <stdlib.h>
#include <limits.h>
#include <io.h>
#include <stdio.h>
#define BAIL_ON_NULL(p) if (!(p)) {goto error;}
#define BAIL_ON_FAILURE(hr) if (FAILED(hr)) {goto error;}
 
#include "activeds.h"
#include "main.hxx"
// Globals representing parameters on IDirectorySearch
LPWSTR pszSearchBase, pszSearchFilter, pszAttrNames[10], pszAttrList;
DWORD dwNumberAttributes = -1;
// Preference Values
BOOL fASynchronous=FALSE, fDerefAliases=FALSE, fAttrsOnly=FALSE;
DWORD fSizeLimit, fTimeLimit, dwTimeOut, dwPageSize, dwSearchScope;
 
ADS_SEARCHPREF_INFO pSearchPref[10];
DWORD dwCurrPref = 0;
 
LPWSTR pszUserName=NULL, pszPassword=NULL;
DWORD dwAuthFlags=0;
DWORD cErr=0;
 
char *prefNameLookup[] = 
    {
    "ADS_SEARCHPREF_ASYNCHRONOUS", 
    "ADS_SEARCHPREF_DEREF_ALIASES",   
    "ADS_SEARCHPREF_SIZE_LIMIT",      
    "ADS_SEARCHPREF_TIME_LIMIT",      
    "ADS_SEARCHPREF_ATTRIBTYPES_ONLY",
    "ADS_SEARCHPREF_SEARCH_SCOPE",    
    "ADS_SEARCHPREF_TIMEOUT",         
    "ADS_SEARCHPREF_PAGESIZE",         
    "ADS_SEARCHPREF_PAGED_TIME_LIMIT",
    "ADS_SEARCHPREF_CHASE_REFERRALS"
    };
 
 
//+-----------------------------------------------------------------
//  Function:   main
//------------------------------------------------------------------
INT _CRTAPI1
main(int argc, char * argv[])
{
 
    hr = CoInitialize(NULL);
    hr = ADsOpenObject(
        pszSearchBase,
        pszUserName,
        pszPassword,
        dwAuthFlags,
        IID_IDirectorySearch,
        (void **)&pDSSearch
        );
 
    if (dwCurrPref) {
        hr = pDSSearch->SetSearchPreference(
                 pSearchPref,
                 dwCurrPref
                 );
        BAIL_ON_FAILURE(hr);
        }
 
    hr = pDSSearch->ExecuteSearch(
             pszSearchFilter,
             pszAttrNames,
             dwNumberAttributes,
             &hSearchHandle
              );      BAIL_ON_FAILURE(hr);
 
    hr = pDSSearch->GetNextRow(
             hSearchHandle
             );     BAIL_ON_FAILURE(hr);
 
    while (hr != S_ADS_NOMORE_ROWS) {
        nRows++;
 
        if (dwNumberAttributes == -1) {
            hr = pDSSearch->GetNextColumnName(
                     hSearchHandle,
                     &pszColumnName
                     );             BAIL_ON_FAILURE(hr);
    
            while (hr != S_ADS_NOMORE_COLUMNS) {
                hr = pDSSearch->GetColumn(
                         hSearchHandle,
                         pszColumnName,
                         &Column
                         );
    
                if (FAILED(hr)  && hr != E_ADS_COLUMN_NOT_SET) 
                    goto error;
    
                if (SUCCEEDED(hr)) {
                    PrintColumn(&Column, pszColumnName);
                    pDSSearch->FreeColumn(&Column);
                }
 
             if (pszColumnName)
             free(pszColumnName);
                hr = pDSSearch->GetNextColumnName(
                         hSearchHandle,
                         &pszColumnName
                         );      BAIL_ON_FAILURE(hr);
            }
            printf("\n");
        }                                  
        else {
            for (unsigned int i=0; i<dwNumberAttributes; i++) {
                hr = pDSSearch->GetColumn(
                         hSearchHandle,
                         pszAttrNames[i],
                         &Column
                         );
    
                if (hr == E_ADS_COLUMN_NOT_SET) 
                    continue;
    
                BAIL_ON_FAILURE(hr);
    
                PrintColumn(&Column, pszAttrNames[i]);
    
                pDSSearch->FreeColumn(&Column);
            }                                  
        printf("\n");
        }
 
        hr = pDSSearch->GetNextRow(
                 hSearchHandle
                 );
        BAIL_ON_FAILURE(hr);
    }
 
    wprintf (L"Total Rows: %d\n", nRows);
 
    if (cErr) {
        wprintf (L"%d warning(s) ignored", cErr);
    }
 
    if (hSearchHandle)
        pDSSearch->CloseSearchHandle(hSearchHandle);
 
    FREE_INTERFACE(pDSSearch);
 
    FREE_UNICODE_STRING(pszSearchBase) ;
    FREE_UNICODE_STRING(pszSearchFilter) ;
    FREE_UNICODE_STRING(pszAttrList) ;
 
    CoUninitialize();
 
    return(0) ;
 
error:
//  Error handling 
}