Platform SDK: Active Directory, ADSI, and Directory Services

Reading attributeSchema and classSchema Objects

This section provides sample code and guidelines for reading directly from attributeSchema and classSchema objects in the schema container. Note that in most programming situations when you need to read information about a class or attribute definition, it is better and easier to read the information from the abstract schema as described in Reading the Abstract Schema.

The interfaces and techniques for reading from the schema container are the same ones you'd use to read any other object in Active Directory. Here are the guidelines:

The following sample code binds to an IADsContainer pointer on the schema container and then uses the ADsBuildEnumerator and ADsEnumerateNext functions to enumerate its contents. Note that the enumeration will include all the attributeSchema and classSchema objects as well as a single subSchema object, which is the abstract schema.

For each enumerated object, the sample uses the IADs::get_Class method to determine whether it is an attributeSchema or classSchema object. The sample shows how to read the properties that are not available from the abstract schema.

#include <windows.h>
#include <stdio.h>
#include <activeds.h>

// Forward declarations.
HRESULT ProcessAttribute(IADs *pChild);
HRESULT ProcessClass(IADs *pChild);

// ****************************************************************
//  wmain
// ****************************************************************
int wmain(int argc, WCHAR* argv[])
{
HRESULT hr;
IADs *pRootDSE = NULL;
IADsContainer *pSchema = NULL;  
IEnumVARIANT *pEnum = NULL;
IADs *pChild = NULL;
WCHAR szDSPath[MAX_PATH];
ULONG lFetch;
VARIANT var;
BSTR bstrClass = NULL; 
DWORD dwClasses = 0, dwAttributes = 0, dwUnknownClass = 0;

CoInitialize(NULL);

// Bind to rootDSE to get the schemaNamingContext property.
hr = ADsGetObject(L"LDAP://rootDSE", IID_IADs, (void**)&pRootDSE);
if (FAILED(hr)) {
    wprintf(L"ADsGetObject failed: 0x%x\n", hr);
    goto cleanup;
}
VariantInit(&var);
hr = pRootDSE->Get(L"schemaNamingContext", &var);
wcscpy(szDSPath, L"LDAP://");
wcscat(szDSPath, var.bstrVal);

// Bind to the actual schema container.
wprintf(L"Binding to %s\n", szDSPath);
hr = ADsGetObject(szDSPath, IID_IADsContainer, (void**) &pSchema);
if (FAILED(hr)) {
    wprintf(L"ADsGetObject to schema failed: 0x%x\n", hr);
    goto cleanup;
}

// Enumerate the attribute and class objects in the schema container.
hr = ADsBuildEnumerator( pSchema, &pEnum );
if (FAILED(hr)) {
    wprintf(L"ADsBuildEnumerator failed: 0x%x\n", hr);
    goto cleanup;
}

VariantClear(&var);
hr = ADsEnumerateNext( pEnum, 1, &var, &lFetch );
while( hr == S_OK && lFetch == 1)
{
    // Get an IADs pointer on the child object.
    hr = V_DISPATCH(&var)->QueryInterface( IID_IADs, (void**) &pChild );
    if ( FAILED(hr) ) {
        wprintf(L"Couldn't get child IADs pointer: 0x%x\n", hr);
        goto cleanuploop;
    }

    // Find out if this is a class, attribute, or subSchema object.
    hr = pChild->get_Class(&bstrClass);
    if ( FAILED(hr) ) {
        wprintf(L"Couldn't get_Class: 0x%x\n", hr);
        goto cleanuploop;
    }

    // Get information depending on type of schema element.
    if ( _wcsicmp(L"classSchema", bstrClass)==0 )
    {
        dwClasses++;
        wprintf(L"%s", bstrClass );
        hr = ProcessClass(pChild);
        if (FAILED(hr))
            goto cleanuploop;
        wprintf(L"\n");
    }
    else if ( _wcsicmp(L"attributeSchema", bstrClass)==0 )
    {
        dwAttributes++;
        wprintf(L"%s", bstrClass );
        hr = ProcessAttribute(pChild);
        if (FAILED(hr))
            goto cleanuploop;
        wprintf(L"\n");
    }
    else if ( _wcsicmp(L"subSchema", bstrClass)==0 ) 
    {
        wprintf(L"abstract schema" );
        wprintf(L"\n");
    }
    else
        dwUnknownClass++;
    
cleanuploop:
    if (bstrClass) {
        SysFreeString(bstrClass);
        bstrClass = NULL;
    }
    VariantClear(&var);
    if (SUCCEEDED(hr))
        hr = ADsEnumerateNext( pEnum, 1, &var, &lFetch );
}
wprintf(L"Classes: %u\nAttributes: %u\nUnknown: %u\n", 
        dwClasses, dwAttributes, dwUnknownClass);

cleanup:
if (pEnum)
    ADsFreeEnumerator(pEnum);
if (pSchema)
    pSchema->Release();
VariantClear(&var);

CoUninitialize();

return hr;
}

// ****************************************************************
//  PrintGUIDFromVariant
//  Prints out a GUID in string format.
// ****************************************************************
VOID 
PrintGUIDFromVariant(VARIANT varGUID)
{
HRESULT hr;
void HUGEP *pArray;
WCHAR szGUID[40];
LPGUID pGUID;

DWORD dwLen = sizeof(GUID);

hr = SafeArrayAccessData( V_ARRAY(&varGUID), &pArray );
pGUID = (LPGUID)pArray;

// Convert GUID to string.
::StringFromGUID2(*pGUID, szGUID, 40); 
                                
// Print the GUID
wprintf(L",%s",szGUID);

SafeArrayUnaccessData( V_ARRAY(&varGUID) );
VariantClear(&varGUID);
}

// ****************************************************************
// PrintPropertyValue
// ****************************************************************
VOID PrintPropertyValue(VARIANT var, WCHAR *szText, HRESULT hr) {
if (E_ADS_PROPERTY_NOT_FOUND == hr)
    wprintf(L",-- not set --");
else if (FAILED(hr))
    wprintf(L",get %s failed: 0x%x", szText, hr);
else 
switch (var.vt) 
{
    case VT_BSTR:
        wprintf(L",%s", var.bstrVal);
        break;
    case VT_I4:
        wprintf(L",%u", var.iVal);
         break;
    case VT_BOOL:
        wprintf(L",%s", var.boolVal ? L"TRUE" : L"FALSE");
         break;
    default:
        wprintf(L",-- ??? --");
}
}

// ****************************************************************
//  ProcessAttribute
//  Gets information about an attributeClass object.
// ****************************************************************
HRESULT ProcessAttribute(IADs *pChild)
{
VARIANT var;
HRESULT hr;

// Get the attribute's cn (Common-Name) property. 
VariantClear(&var);
hr = pChild->Get(L"cn", &var);
PrintPropertyValue(var, L"cn", hr);

// Get the attribute's lDAPDisplayName.
VariantInit(&var);
hr = pChild->Get(L"lDAPDisplayName", &var);
PrintPropertyValue(var, L"lDAPDisplayName", hr);

// Get the class's linkID. 
VariantClear(&var);
hr = pChild->Get(L"linkID", &var);
PrintPropertyValue(var, L"linkID", hr);

// Get the attribute's schemaIDGUID. 
VariantClear(&var);
hr = pChild->Get(L"schemaIDGUID", &var);
if (FAILED(hr))
    wprintf(L",get schemaIDGUID failed: 0x%x", hr);
else 
    PrintGUIDFromVariant(var);

// Get the attribute's attributeSecurityGUID. 
VariantClear(&var);
hr = pChild->Get(L"attributeSecurityGUID", &var);
if (E_ADS_PROPERTY_NOT_FOUND == hr)
    wprintf(L",-- not set --");
else if (FAILED(hr))
    wprintf(L",get attributeSecurityGUID failed: 0x%x", hr);
else 
    PrintGUIDFromVariant(var);

// Get the attribute's attributeSyntax property. 
VariantClear(&var);
hr = pChild->Get(L"attributeSyntax", &var);
PrintPropertyValue(var, L"attributeSyntax", hr);

// Get the attribute's oMSyntax property. 
VariantClear(&var);
hr = pChild->Get(L"oMSyntax", &var);
PrintPropertyValue(var, L"oMSyntax", hr);

return (E_ADS_PROPERTY_NOT_FOUND == hr) ? 0 : hr;
}

// ****************************************************************
// ProcessClass
// Gets information about a schema class.
// ****************************************************************
HRESULT ProcessClass(IADs *pChild)
{
VARIANT var;
HRESULT hr;

// Get the class's cn.
VariantInit(&var);
hr = pChild->Get(L"cn", &var);
PrintPropertyValue(var, L"cn", hr);

// Get the class's lDAPDisplayName.
VariantInit(&var);
hr = pChild->Get(L"lDAPDisplayName", &var);
PrintPropertyValue(var, L"lDAPDisplayName", hr);

// Get the class's schemaIDGUID. 
VariantClear(&var);
hr = pChild->Get(L"schemaIDGUID", &var);
if (FAILED(hr))
    wprintf(L",get schemaIDGUID failed: 0x%x", hr);
else 
    PrintGUIDFromVariant(var);

// Get the class's adminDescription property. 
VariantClear(&var);
hr = pChild->Get(L"adminDescription", &var);
PrintPropertyValue(var, L"adminDescription", hr);

// Get the class's adminDisplayName property. 
VariantClear(&var);
hr = pChild->Get(L"adminDisplayName", &var);
PrintPropertyValue(var, L"adminDisplayName", hr);

// Get the class's rDNAttID. 
VariantClear(&var);
hr = pChild->Get(L"rDNAttID", &var);
PrintPropertyValue(var, L"rDNAttID", hr);

// Get the class's defaultHidingValue. 
VariantClear(&var);
hr = pChild->Get(L"defaultHidingValue", &var);
PrintPropertyValue(var, L"defaultHidingValue", hr);

// Get the class's defaultObjectCategory. 
VariantClear(&var);
hr = pChild->Get(L"defaultObjectCategory", &var);
PrintPropertyValue(var, L"defaultObjectCategory", hr);

// Get the class's systemOnly value.
VariantClear(&var);
hr = pChild->Get(L"systemOnly", &var);
PrintPropertyValue(var, L"systemOnly", hr);

// Get the class's defaultSecurityDescriptor.
VariantClear(&var);
hr = pChild->Get(L"defaultSecurityDescriptor", &var);
PrintPropertyValue(var, L"defaultSecurityDescriptor", hr);

return (E_ADS_PROPERTY_NOT_FOUND == hr) ? 0 : hr;
}