MAIN.CXX
//---------------------------------------------------------------------------- 
// 
//  Microsoft Active Directory 1.1 Sample Code 
// 
//  Copyright (C) Microsoft Corporation, 1996 
// 
//  File:       main.cxx 
// 
//  Contents:   Main for adsqry 
// 
// 
//---------------------------------------------------------------------------- 
 
#include "main.hxx" 
 
 
#define MAX_SIZE 10 
//  
// Globals representing the properties 
// 
 
DBPROPSET          rgDBPropSet[MAX_SIZE], rgCmdPropSet[MAX_SIZE]; 
DBPROP             rgDBProp[MAX_SIZE], rgCmdProp[MAX_SIZE]; 
 
ULONG              cDBPropSet, cCmdPropSet, cDBProp, cCmdProp; 
 
LPWSTR pszCommandText; 
 
GUID               rguidDialect = DBGUID_DEFAULT; 
 
DWORD cErr; 
 
int __cdecl 
main( int argc, char ** argv) 
{ 
 
    HRESULT            hr; 
    ULONG              i, j; 
    HROW             * phRows; 
 
    WCHAR              pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH]; 
    DWORD              dwError; 
                          
    OLECHAR          * szColNames = NULL; 
    DBCOLUMNINFO     * prgColInfo = NULL; 
    DBCOLUMNINFO     * rgInfo = NULL; 
    WCHAR            * pStringBuffer = NULL; 
    WCHAR            * pColInfoBuffer = NULL; 
 
    IMalloc          * pIMalloc = NULL; 
    IDBInitialize    * pIDBInit = NULL; 
    IDBCreateSession * pIDBCS = NULL; 
    IDBCreateCommand * pIDBCreateCommand = NULL; 
    ICommandText     * pICommandText = NULL; 
    ICommand         * pICommand = NULL; 
    IRowset          * pIRowset = NULL; 
    IAccessor        * pAccessor = NULL; 
    IColumnsInfo     * pIColsInfo = NULL; 
    ULONG              cCol, cRowsObtained, nAttrs; 
 
    Data             * pMyData = NULL; 
    DBBINDSTATUS     * pMyStatus = NULL; 
    HACCESSOR          myAccessor = NULL; 
 
    ICommandProperties * pICommandProperties; 
    IDBProperties * pIDBProperties; 
 
 
    hr = ProcessArgs(argc, argv); 
    BAIL_ON_FAILURE(hr); 
 
    hr = CoInitialize(NULL); 
    if (FAILED(hr)) { 
        printf("CoInitialize failed\n"); 
        exit(1); 
    } 
 
    // 
    // Instantiate a data source object for LDAP provider 
    // 
    hr = CoCreateInstance( 
             CLSID_ADsDSOObject, 
             0, 
             CLSCTX_INPROC_SERVER, 
             IID_IDBInitialize, 
             (void **)&pIDBInit 
             ); 
    if(FAILED(hr)) { 
        printf("CoCreateInstance failed \n"); 
        goto error; 
    } 
 
    // 
    // Initialize the Data Source 
    // 
    hr = pIDBInit->Initialize(); 
    if(FAILED(hr)) { 
        printf("IDBIntialize::Initialize failed \n"); 
        goto error; 
    } 
 
    if (cDBPropSet) { 
        pIDBInit->QueryInterface( 
            IID_IDBProperties, 
            (void**) &pIDBProperties); 
        if(FAILED(hr)) { 
            printf("QueryInterface for IDBProperties failed \n"); 
            goto error; 
        } 
     
        hr = pIDBProperties->SetProperties( 
                 cDBPropSet, 
                 rgDBPropSet); 
     
        if(FAILED(hr)) { 
            printf("IDBProperties->SetProperties failed \n"); 
            goto error; 
        } 
     
        FREE_INTERFACE(pIDBProperties); 
    } 
 
    pIDBInit->QueryInterface( 
        IID_IDBCreateSession, 
        (void**) &pIDBCS); 
    if(FAILED(hr)) { 
        printf("QueryInterface for IDBCreateSession failed \n"); 
        goto error; 
    } 
 
    FREE_INTERFACE(pIDBInit); 
 
    // 
    // Create a session returning a pointer to its CreateCommand interface 
    // 
    hr = pIDBCS->CreateSession( 
             NULL, 
             IID_IDBCreateCommand, 
             (LPUNKNOWN*) &pIDBCreateCommand 
             ); 
    if(FAILED(hr)) { 
        printf("IDBCreateSession::CreateSession failed \n"); 
        goto error; 
    } 
 
    FREE_INTERFACE(pIDBCS); 
 
    // 
    // Create a command from the session object 
    // 
    hr = pIDBCreateCommand->CreateCommand( 
             NULL, 
             IID_ICommandText, 
             (LPUNKNOWN*) &pICommandText 
             ); 
 
    if(FAILED(hr)) { 
        printf(" IDBCreateCommand::CreateCommand failed\n"); 
        goto error; 
    } 
 
    FREE_INTERFACE(pIDBCreateCommand); 
 
    // 
    // Set the CommandText for the Query 
    // 
    hr = pICommandText->SetCommandText( 
             rguidDialect, 
             pszCommandText 
             ); 
 
    if(FAILED(hr)) { 
        printf("ICommandText::SetCommandText failed \n"); 
        goto error; 
    } 
 
 
    if (cCmdPropSet) { 
        hr = pICommandText->QueryInterface( 
                 IID_ICommandProperties, 
                 (void**) &pICommandProperties); 
     
        if(FAILED(hr)) { 
            printf("QueryInterface for ICommandProperties failed \n"); 
            goto error; 
        } 
     
        hr = pICommandProperties->SetProperties( 
                 cCmdPropSet, 
                 rgCmdPropSet); 
     
        if(FAILED(hr)) { 
            printf("ICommandProperties:;SetProperties failed \n"); 
            goto error; 
        } 
     
        FREE_INTERFACE(pICommandProperties); 
    } 
 
    hr = pICommandText->QueryInterface( 
             IID_ICommand, 
             (void**) &pICommand); 
 
    if(FAILED(hr)) { 
        printf("QueryInterface for ICommand failed \n"); 
        goto error; 
    } 
 
    FREE_INTERFACE(pICommandText); 
 
    // 
    // Do the Query and get back a rowset 
    // 
    hr = pICommand->Execute( 
             NULL, 
             IID_IRowset, 
             NULL, 
             NULL, 
             (LPUNKNOWN *)&pIRowset 
             ); 
    if(FAILED(hr)) { 
        printf("ICommand::Execute failed \n"); 
        goto error; 
    } 
 
    FREE_INTERFACE(pICommand); 
 
    hr = pIRowset->QueryInterface( 
             IID_IColumnsInfo, 
             (void**) &pIColsInfo 
             ); 
    if(FAILED(hr)) { 
        printf("QueryInterface for IColumnsInfo failed \n"); 
        goto error; 
    } 
 
    hr = pIColsInfo->GetColumnInfo( 
             &cCol, 
             &prgColInfo, 
             &szColNames 
             ); 
    if(FAILED(hr)) { 
        printf("IColumnsInfo::GetColumnInfo failed \n"); 
        goto error; 
    } 
 
    // 
    // The no. of attributes is one less than the no. of columns because of 
    // the Bookmark column 
    // 
    nAttrs = cCol - 1; 
 
 
    pMyStatus = (DBBINDSTATUS *) LocalAlloc( 
                                     LPTR, 
                                     sizeof(DBBINDSTATUS) * nAttrs 
                                     ); 
    BAIL_ON_NULL(pMyStatus); 
 
    hr = CreateAccessorHelper( 
             pIRowset, 
             nAttrs, 
             prgColInfo, 
             &myAccessor, 
             pMyStatus 
             ); 
    if(FAILED(hr)) { 
        printf("CreateAccessorHelper failed \n"); 
        goto error; 
    } 
 
 
    pMyData = (Data *) LocalAlloc( 
                           LPTR, 
                           sizeof(Data) * nAttrs 
                           ); 
    if(!pMyData) { 
        hr = E_OUTOFMEMORY; 
        goto error; 
    } 
 
    // 
    //  Get the rows; 256 at a time 
    // 
    phRows = NULL; 
    hr = pIRowset->GetNextRows( 
             NULL, 
             0, 
             256, 
             &cRowsObtained, 
             &phRows 
             ); 
    if(FAILED(hr)) { 
        printf("IRowset::GetNextRows failed \n"); 
        goto error; 
    } 
 
    j = cRowsObtained; 
    while (cRowsObtained) { 
        for (i = 0; i < cRowsObtained; i++) { 
            // 
            // Get the data from each row 
            // 
            hr = pIRowset->GetData( 
                     phRows[i], 
                     myAccessor, 
                     (void*)pMyData 
                     ); 
            if(FAILED(hr)) { 
                printf("IRowset::GetData failed \n"); 
                goto error; 
            } 
     
            PrintData(pMyData, nAttrs, prgColInfo); 
        } 
 
        pIRowset->ReleaseRows( 
                      cRowsObtained,  
                      phRows, 
                      NULL, 
                      NULL, 
                      NULL 
                      ); 
 
        // 
        // Get the next 256 rows 
        //        
 
        hr = pIRowset->GetNextRows( 
                 NULL, 
                 0, 
                 256, 
                 &cRowsObtained, 
                 &phRows 
                 ); 
        if(FAILED(hr)) { 
            printf("IRowset::GetNextRows failed \n"); 
            goto error; 
        } 
        j+=cRowsObtained; 
    } 
 
 
    printf("Rows printed = %d\n", j); 
 
    FREE_STRING(pszCommandText); 
 
    CoGetMalloc(MEMCTX_TASK, &pIMalloc); 
    IMALLOC_FREE(pIMalloc, prgColInfo); 
    IMALLOC_FREE(pIMalloc, szColNames); 
 
    FREE_INTERFACE(pIMalloc); 
    FREE_INTERFACE(pAccessor); 
    FREE_INTERFACE(pIColsInfo); 
    FREE_INTERFACE(pIRowset); 
 
    LOCAL_FREE(pMyStatus); 
    LOCAL_FREE(pMyData); 
 
    // 
    // Uninitialize OLE. 
    // 
    CoUninitialize(); 
 
    exit(0); 
 
error: 
 
 
    CoGetMalloc(MEMCTX_TASK, &pIMalloc); 
    IMALLOC_FREE(pIMalloc, prgColInfo); 
    IMALLOC_FREE(pIMalloc, szColNames); 
 
    FREE_STRING(pszCommandText); 
 
    FREE_INTERFACE(pIMalloc); 
    FREE_INTERFACE(pIDBInit); 
    FREE_INTERFACE(pIDBCS); 
    FREE_INTERFACE(pIDBCreateCommand); 
    FREE_INTERFACE(pICommandText); 
    FREE_INTERFACE(pICommand); 
    FREE_INTERFACE(pIRowset); 
    FREE_INTERFACE(pIColsInfo); 
    FREE_INTERFACE(pAccessor); 
 
    LOCAL_FREE(pMyStatus); 
    LOCAL_FREE(pMyData); 
 
    printf("Errors stopped the Query; hr = %x", hr); 
 
    if(hr == ERROR_EXTENDED_ERROR) { 
        hr = ADsGetLastError( 
                 &dwError, 
                 pszErrorBuf, 
                 MAX_PATH, 
                 pszNameBuf, 
                 MAX_PATH 
                 ); 
    } 
 
    if(SUCCEEDED(hr)) { 
        wprintf(L"Error in %s; %s\n", pszNameBuf, pszErrorBuf); 
    } 
 
    exit(1); 
    return(0); 
} 
 
 
 
//+--------------------------------------------------------------------------- 
// 
//  Function:   ProcessArgs 
// 
//  Synopsis: 
// 
//---------------------------------------------------------------------------- 
 
HRESULT  
ProcessArgs( 
    int argc, 
    char * argv[] 
    ) 
{ 
    argc--; 
    int currArg = 1; 
    LPWSTR pTemp = NULL; 
    char *pszCurrPref = NULL, *pszCurrPrefValue = NULL; 
 
    LPWSTR pszSearchBase = NULL, pszSearchFilter = NULL, pszAttrList = NULL; 
    LPWSTR pszUserName = NULL, pszPassword = NULL; 
    DWORD dwAuthFlags; 
 
    cCmdProp = cDBProp = 0; 
 
    while (argc) { 
        if (argv[currArg][0] != '/' && argv[currArg][0] != '-')  
            BAIL_ON_FAILURE (E_FAIL); 
        switch (argv[currArg][1]) { 
        case 'b': 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
            pszSearchBase = AllocateUnicodeString(argv[currArg]); 
            BAIL_ON_NULL(pszSearchBase); 
            break; 
 
        case 'f': 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
            pszSearchFilter = AllocateUnicodeString(argv[currArg]); 
            BAIL_ON_NULL(pszSearchFilter); 
            break; 
 
        case 'd': 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
 
            if (!_stricmp(argv[currArg], "sql"))  
                rguidDialect = DBGUID_SQL;      
            else if (!_stricmp(argv[currArg], "ldap"))  
                rguidDialect = DBGUID_LDAPDialect;      
            else if (!_stricmp(argv[currArg], "default"))  
                rguidDialect = DBGUID_DEFAULT;      
            else  
                BAIL_ON_FAILURE (E_FAIL); 
 
            break; 
 
        case 'a': 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
            pszAttrList = AllocateUnicodeString(argv[currArg]); 
            BAIL_ON_NULL(pszAttrList); 
 
            break; 
 
        case 'u': 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
            pszUserName = AllocateUnicodeString(argv[currArg]); 
            BAIL_ON_NULL(pszUserName); 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
            pszPassword = AllocateUnicodeString(argv[currArg]); 
            BAIL_ON_NULL(pszPassword); 
 
            rgDBProp[cDBProp].dwPropertyID = DBPROP_AUTH_USERID; 
            rgDBProp[cDBProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
            rgDBProp[cDBProp].vValue.vt = VT_BSTR; 
            V_BSTR (&rgDBProp[cDBProp].vValue) = SysAllocString(pszUserName); 
            cDBProp++; 
 
 
            rgDBProp[cDBProp].dwPropertyID = DBPROP_AUTH_PASSWORD; 
            rgDBProp[cDBProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
            rgDBProp[cDBProp].vValue.vt = VT_BSTR; 
            V_BSTR (&rgDBProp[cDBProp].vValue) = SysAllocString(pszPassword); 
            cDBProp++; 
 
            break; 
 
        case 'p': 
            argc--; 
            currArg++; 
            if (argc <= 0) 
                BAIL_ON_FAILURE (E_FAIL); 
 
            pszCurrPref = strtok(argv[currArg], "="); 
            pszCurrPrefValue = strtok(NULL, "="); 
            if (!pszCurrPref || !pszCurrPrefValue)  
                BAIL_ON_FAILURE(E_FAIL); 
 
            if (!_stricmp(pszCurrPref, "asynchronous")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_ASYNCHRONOUS; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_BOOL; 
                if (!_stricmp(pszCurrPrefValue, "yes" ))  
                    V_BOOL (&rgCmdProp[cCmdProp].vValue) = VARIANT_TRUE; 
                else if (!_stricmp(pszCurrPrefValue, "no" ))  
                    V_BOOL (&rgCmdProp[cCmdProp].vValue) = VARIANT_FALSE; 
                else  
                    BAIL_ON_FAILURE(E_FAIL); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "attrTypesOnly")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_ATTRIBTYPES_ONLY; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_BOOL; 
                if (!_stricmp(pszCurrPrefValue, "yes" ))  
                    V_BOOL (&rgCmdProp[cCmdProp].vValue) = VARIANT_TRUE; 
                else if (!_stricmp(pszCurrPrefValue, "no" ))  
                    V_BOOL (&rgCmdProp[cCmdProp].vValue) = VARIANT_FALSE; 
                else  
                    BAIL_ON_FAILURE(E_FAIL); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "SecureAuth")) { 
                if (!_stricmp(pszCurrPrefValue, "yes" ))  
                    dwAuthFlags |= ADS_SECURE_AUTHENTICATION; 
                else if (!_stricmp(pszCurrPrefValue, "no" ))  
                    dwAuthFlags &= ~ADS_SECURE_AUTHENTICATION; 
                else  
                    BAIL_ON_FAILURE(E_FAIL); 
 
                rgDBProp[cDBProp].dwPropertyID = DBPROP_AUTH_ENCRYPT_PASSWORD; 
                rgDBProp[cDBProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgDBProp[cDBProp].vValue.vt = VT_BSTR; 
                V_BSTR (&rgDBProp[cDBProp].vValue) = SysAllocString(pszPassword); 
                cDBProp++; 
     
            } 
            else if (!_stricmp(pszCurrPref, "derefAliases")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_DEREF_ALIASES; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_BOOL; 
                if (!_stricmp(pszCurrPrefValue, "yes" ))  
                    V_BOOL (&rgCmdProp[cCmdProp].vValue) = VARIANT_TRUE; 
                else if (!_stricmp(pszCurrPrefValue, "no" ))  
                    V_BOOL (&rgCmdProp[cCmdProp].vValue) = VARIANT_FALSE; 
                else  
                    BAIL_ON_FAILURE(E_FAIL); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "timeOut")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_TIMEOUT; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                V_I4 (&rgCmdProp[cCmdProp].vValue) = atoi(pszCurrPrefValue); 
                cCmdProp++; 
            }                                          
            else if (!_stricmp(pszCurrPref, "timeLimit")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_TIME_LIMIT; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                V_I4 (&rgCmdProp[cCmdProp].vValue) = atoi(pszCurrPrefValue); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "sizeLimit")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_SIZE_LIMIT; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                V_I4 (&rgCmdProp[cCmdProp].vValue) = atoi(pszCurrPrefValue); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "PageSize")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_PAGESIZE; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                V_I4 (&rgCmdProp[cCmdProp].vValue) = atoi(pszCurrPrefValue); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "PagedTimeLimit")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_PAGED_TIME_LIMIT; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                V_I4 (&rgCmdProp[cCmdProp].vValue) = atoi(pszCurrPrefValue); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "SearchScope")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_SEARCH_SCOPE; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                if (!_stricmp(pszCurrPrefValue, "Base" ))  
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_SCOPE_BASE; 
                else if (!_stricmp(pszCurrPrefValue, "OneLevel" ))  
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_SCOPE_ONELEVEL; 
                else if (!_stricmp(pszCurrPrefValue, "Subtree" ))  
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_SCOPE_SUBTREE; 
                else  
                    BAIL_ON_FAILURE(E_FAIL); 
                cCmdProp++; 
            } 
            else if (!_stricmp(pszCurrPref, "ChaseReferrals")) { 
                rgCmdProp[cCmdProp].dwPropertyID = ADSIPROP_CHASE_REFERRALS; 
                rgCmdProp[cCmdProp].dwOptions = DBPROPOPTIONS_REQUIRED; 
                rgCmdProp[cCmdProp].vValue.vt = VT_I4; 
                if (!_stricmp(pszCurrPrefValue, "always" )) 
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_CHASE_REFERRALS_ALWAYS; 
                else if (!_stricmp(pszCurrPrefValue, "never" )) 
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_CHASE_REFERRALS_NEVER; 
                else if (!_stricmp(pszCurrPrefValue, "external" )) 
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_CHASE_REFERRALS_EXTERNAL; 
                else if (!_stricmp(pszCurrPrefValue, "subordinate" )) 
                    V_I4 (&rgCmdProp[cCmdProp].vValue) = ADS_CHASE_REFERRALS_SUBORDINATE; 
                else 
                    BAIL_ON_FAILURE(E_FAIL); 
                cCmdProp++; 
            } 
            else  
                BAIL_ON_FAILURE(E_FAIL); 
 
            break; 
 
        default:  
            BAIL_ON_FAILURE(E_FAIL); 
        } 
 
        argc--; 
        currArg++; 
    } 
 
    // 
    // Check for Mandatory arguments; 
    // 
 
    if (!pszSearchBase || !pszSearchFilter || !pszAttrList)  
        BAIL_ON_FAILURE(E_FAIL); 
 
    if (IsEqualGUID(rguidDialect, DBGUID_SQL) ) { 
          
        pszCommandText = (LPWSTR) AllocADsMem( 
                                      (wcslen(pszSearchBase) + 
                                      wcslen(pszSearchFilter) + 
                                      wcslen(pszAttrList) + 
                                      wcslen(L"''") + 
                                      wcslen(L"SELECT ") +  
                                      wcslen(L" FROM ") +  
                                      wcslen(L" WHERE ") +  
                                      1) * sizeof(WCHAR) 
                                      ); 
        BAIL_ON_NULL(E_FAIL); 
     
        wsprintf(pszCommandText,  
                 L"SELECT %s FROM '%s' WHERE %s",  
                 pszAttrList, 
                 pszSearchBase,  
                 pszSearchFilter 
                 ); 
     
    } else { 
 
        pszCommandText = (LPWSTR) AllocADsMem( 
                                      (wcslen(pszSearchBase) + 
                                      wcslen(pszSearchFilter) + 
                                      wcslen(pszAttrList) + 
                                      5) * sizeof(WCHAR) 
                                      ); 
        BAIL_ON_NULL(E_FAIL); 
     
        wsprintf(pszCommandText,  
                 L"<%s>;%s;%s",  
                 pszSearchBase,  
                 pszSearchFilter, 
                 pszAttrList 
                 ); 
 
    } 
    if (cDBProp > 0) { 
        cDBPropSet = 1; 
        rgDBPropSet[0].rgProperties    = rgDBProp; 
        rgDBPropSet[0].cProperties     = cDBProp; 
        rgDBPropSet[0].guidPropertySet = DBPROPSET_DBINIT; 
    } 
 
    if (cCmdProp > 0) { 
        cCmdPropSet = 1; 
        rgCmdPropSet[0].rgProperties    = rgCmdProp; 
        rgCmdPropSet[0].cProperties     = cCmdProp; 
        rgCmdPropSet[0].guidPropertySet = DBPROPSET_ADSISEARCH; 
    } 
 
    FreeUnicodeString(pszSearchBase) ; 
    FreeUnicodeString(pszSearchFilter) ; 
    FreeUnicodeString(pszAttrList) ; 
 
    return (S_OK); 
 
error: 
 
    FreeUnicodeString(pszSearchBase) ; 
    FreeUnicodeString(pszSearchFilter) ; 
    FreeUnicodeString(pszAttrList) ; 
 
    PrintUsage(); 
    return E_FAIL; 
     
}