Example Code for Searching for Schema Objects

This topic includes a code example used to search for schema objects.

The following C++ code example shows how to search for schema objects that have bits set in the systemFlags attribute.

#include <stdio.h>
#include <atlbase.h>
#include <activeds.h>
#include <ntldap.h>

/***************************************************************************

    PrintAttributesByType()

    Searches for and prints all attributeSchema objects that contain all of 
    the specified attribute type flags.

    Parameters:

    pSchemaNC - IDirectorySearch pointer to schema naming context.

    dwAttributeType - Bit flags to search for in systemFlags. These are 
        values such as ADS_SYSTEMFLAG_ATTR_IS_CONSTRUCTED.

    bIsExactMatch - TRUE to find attributes that have systemFlags exactly 
        matching dwAttributeType. FALSE to find attributes that have the 
        dwAttributeType bit set, and possibly others.

***************************************************************************/

HRESULT PrintAttributesByType(IDirectorySearch *pSchemaNC,
        DWORD dwAttributeType,
        BOOL bIsExactMatch)
{
    HRESULT hr;

    // Attributes are one-level deep in the Schema container, so only search one level.
    ADS_SEARCHPREF_INFO SearchPrefs[2];
    SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
    SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
    SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
 
    // Use paging if there are more properties than can be returned by one page.
    SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
    SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
    SearchPrefs[1].vValue.Integer = 1000;

    // Set the search preferences.
    hr = pSchemaNC->SetSearchPreference(SearchPrefs, sizeof(SearchPrefs)/sizeof(ADS_SEARCHPREF_INFO));
    if(FAILED(hr))
    {
        return hr;
    }
 
    // Handle that is used for searching.
    ADS_SEARCH_HANDLE hSearch;
 
    LPWSTR rgpwszAttributes[] = {L"cn"};
    DWORD dwAttributes = sizeof(rgpwszAttributes)/sizeof(LPWSTR);

    // Create the search filter.
    WCHAR wszAttributeType[30]; // Plenty large enough to handle the biggest 32-bit number.
    swprintf_s(wszAttributeType, L"%d", dwAttributeType);

    CComBSTR sbstrSearchFilter;
    if (bIsExactMatch)
    {
        sbstrSearchFilter = "(&(objectCategory=attributeSchema)(systemFlags=";
        sbstrSearchFilter += wszAttributeType;
        sbstrSearchFilter += "))";
    }
    else
    {
        sbstrSearchFilter = "(&(objectCategory=attributeSchema)(systemFlags:";
        sbstrSearchFilter += LDAP_MATCHING_RULE_BIT_AND;
        sbstrSearchFilter += ":=";
        sbstrSearchFilter += wszAttributeType;
        sbstrSearchFilter += "))";
    }
 
    // Execute the search.
    hr = pSchemaNC->ExecuteSearch(sbstrSearchFilter,
                                  rgpwszAttributes,
                                  dwAttributes,
                                  &hSearch);
    if(SUCCEEDED(hr))
    {
        // Get the first row of results.
        hr = pSchemaNC->GetFirstRow(hSearch);

        while(S_OK == hr)
        {
            ADS_SEARCH_COLUMN col;

            // Print each column.
            for(DWORD i = 0; i < dwAttributes; i++)
            {
                hr = pSchemaNC->GetColumn(hSearch, rgpwszAttributes[i], &col);
                if(SUCCEEDED(hr))
                {
                    // Print the data for the column and free the column.
                    if (col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
                    {
                        wprintf(L"%s:", rgpwszAttributes[i]); 

                        // Print each attribute value.
                        for(DWORD x = 0; x < col.dwNumValues; x++)
                        {
                            wprintf(L"\t%s\n", col.pADsValues[x].CaseIgnoreString); 
                        }
                    }
                    else
                    {
                        wprintf(L"<%s property is not a string>", rgpwszAttributes[0]);
                    }
                    
                    // Free the column.
                    pSchemaNC->FreeColumn(&col);
                }
            }

            // Get the next set of results.
            hr = pSchemaNC->GetNextRow(hSearch);
        }

        // Close the search handle to cleanup.
        pSchemaNC->CloseSearchHandle(hSearch);
    } 

    return hr;
}

The following C and C++ code example shows how to search for schema objects replicated to the global catalog.

#include <stdio.h>
#include <atlbase.h>
#include <activeds.h>
#include <ntldap.h>

/***************************************************************************

    PrintGCAttributes()

    Searches for and prints all attributeSchema objects replicated 
    to the global catalog.

    Parameters:
    
    pSchemaNC - IDirectorySearch pointer to schema naming context.
    
***************************************************************************/

HRESULT PrintGCAttributes(IDirectorySearch *pSchemaNC)
{
    HRESULT hr;

    // Attributes are one-level deep in the Schema container, so only search one level.
    ADS_SEARCHPREF_INFO SearchPrefs[2];
    SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
    SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
    SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
 
    // Use paging if there are more properties than can be returned by one page.
    SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
    SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
    SearchPrefs[1].vValue.Integer = 1000;

    // Set the search preferences.
    hr = pSchemaNC->SetSearchPreference(SearchPrefs, sizeof(SearchPrefs)/sizeof(ADS_SEARCHPREF_INFO));
    if(FAILED(hr))
    {
        return hr;
    }
 
    // Handle used for search.
    ADS_SEARCH_HANDLE hSearch;
 
    LPWSTR rgpwszAttributes[] = {L"cn"};
    DWORD dwAttributes = sizeof(rgpwszAttributes)/sizeof(LPWSTR);

    // Create the search filter.
    LPWSTR pwszSearchFilter = L"(&(objectCategory=attributeSchema)(isMemberOfPartialAttributeSet=TRUE))";
 
    // Execute the search.
    hr = pSchemaNC->ExecuteSearch(pwszSearchFilter,
                                  rgpwszAttributes,
                                  dwAttributes,
                                  &hSearch);
    if(SUCCEEDED(hr))
    {
        // Get the first row of results.
        hr = pSchemaNC->GetFirstRow(hSearch);

        while(S_OK == hr)
        {
            ADS_SEARCH_COLUMN col;

            // Print each column.
            for(DWORD i = 0; i < dwAttributes; i++)
            {
                hr = pSchemaNC->GetColumn(hSearch, rgpwszAttributes[i], &col);
                if(SUCCEEDED(hr))
                {
                    // Print the data for the column and free the column.
                    if (col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
                    {
                        wprintf(L"%s:", rgpwszAttributes[i]); 

                        // Print each attribute value.
                        for(DWORD x = 0; x < col.dwNumValues; x++)
                        {
                            wprintf(L"\t%s\n", col.pADsValues[x].CaseIgnoreString); 
                        }
                    }
                    else
                    {
                        wprintf(L"<%s property is not a string>", rgpwszAttributes[0]);
                    }
                    
                    // Free the column.
                    pSchemaNC->FreeColumn(&col);
                }
            }

            // Get the next set of results.
            hr = pSchemaNC->GetNextRow(hSearch);
        }

        // Close the search handle to cleanup.
        pSchemaNC->CloseSearchHandle(hSearch);
    } 

    return hr;
}

The following C and C++ code example shows how to search for indexed schema objects.

#include <stdio.h>
#include <atlbase.h>
#include <activeds.h>
#include <ntldap.h>

/***************************************************************************

    PrintIndexedAttributes()

    Searches for, and prints, all indexed attributeSchema objects.

    Parameters:

    pSchemaNC - IDirectorySearch pointer to schema naming context.

***************************************************************************/

HRESULT PrintIndexedAttributes(IDirectorySearch *pSchemaNC)
{
    HRESULT hr;

    // Attributes are one-level deep in the Schema container, so only search one level.
    ADS_SEARCHPREF_INFO SearchPrefs[2];
    SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
    SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
    SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
 
    // Use paging in the case that there are more properties than can be returned by one page.
    SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
    SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
    SearchPrefs[1].vValue.Integer = 1000;

    // Set the search preferences.
    hr = pSchemaNC->SetSearchPreference(SearchPrefs, sizeof(SearchPrefs)/sizeof(ADS_SEARCHPREF_INFO));
    if(FAILED(hr))
    {
        return hr;
    }
 
    // Handle used for search.
    ADS_SEARCH_HANDLE hSearch;
 
    LPWSTR rgpwszAttributes[] = {L"cn"};
    DWORD dwAttributes = sizeof(rgpwszAttributes)/sizeof(LPWSTR);

    /*
    Create the search filter. Indexed attributes have the least significant bit 
    of the searchFlags attribute set to 1.
    */
    CComBSTR sbstrSearchFilter;    
    sbstrSearchFilter = "(&(objectCategory=attributeSchema)(searchFlags:";
    sbstrSearchFilter += LDAP_MATCHING_RULE_BIT_AND;
    sbstrSearchFilter += ":=1))";
 
    // Execute the search.
    hr = pSchemaNC->ExecuteSearch(sbstrSearchFilter,
                                  rgpwszAttributes,
                                  dwAttributes,
                                  &hSearch);
    if(SUCCEEDED(hr))
    {
        // Get the first row of results.
        hr = pSchemaNC->GetFirstRow(hSearch);

        while(S_OK == hr)
        {
            ADS_SEARCH_COLUMN col;

            // Print each column.
            for(DWORD i = 0; i < dwAttributes; i++)
            {
                hr = pSchemaNC->GetColumn(hSearch, rgpwszAttributes[i], &col);
                if(SUCCEEDED(hr))
                {
                    // Print the data for the column and free the column.
                    if (col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
                    {
                        wprintf(L"%s:", rgpwszAttributes[i]); 

                        // Print each attribute value.
                        for(DWORD x = 0; x < col.dwNumValues; x++)
                        {
                            wprintf(L"\t%s\n", col.pADsValues[x].CaseIgnoreString); 
                        }
                    }
                    else
                    {
                        wprintf(L"<%s property is not a string>", rgpwszAttributes[0]);
                    }
                    
                    // Free the column.
                    pSchemaNC->FreeColumn(&col);
                }
            }

            // Get the next set of results.
            hr = pSchemaNC->GetNextRow(hSearch);
        }

        // Close the search handle to cleanup.
        pSchemaNC->CloseSearchHandle(hSearch);
    } 

    return hr;
}