Platform SDK: Active Directory, ADSI, and Directory Services

Object Class and Object Category

Each instance of an object class has a multi-valued objectClass property that identifies the class of which the object is an instance, as well as all structural or abstract superclasses from which that class is derived. Thus, the objectClass property of a user object would identify the top, person, organizationalPerson, and user classes. The objectClass property does not include auxiliary classes in the list. The system sets the objectClass value when the object instance is created and it cannot be changed.

Each instance of an object class also has an objectCategory property, which is a single-valued property that contains the distinguished name (DN) of either the class of which the object is an instance or one of its superclasses. When an object is created, the system sets its objectCategory property to the value specified by the defaultObjectCategory property of its object class. An object's objectCategory property cannot be changed.

For sample code that retrieves an object's objectClass property, see Retrieving the objectClass Property.

Important  The objectClass attribute is not indexed. This is because it has multiple values and is highly non-unique; that is, every instance of the objectClass attribute includes the top class. This means an index would be very large and ineffective. To locate objects of a given class, use the objectCategory attribute, which is single-valued and indexed. For more information on using these properties in search filters, see Deciding What to Find.

For most classes, the defaultObjectCategory is the DN of the class's classSchema object. For example, the defaultObjectCategory for the organizationalUnit class is "CN=Organizational-Unit,CN=Schema,CN=Configuration,<DC=forestroot>". However, some classes refer to another class as their defaultObjectCategory. This allows a query to readily find groups of related objects, even if they are of differing classes. For example, the user, person, organizationalPerson, and contact classes all identify the person class in their defaultObjectCategory properties. This allows search filters like (objectCategory=person) to locate instances of all these classes with a single query. Queries for "people" are very common, so this is a simple optimization.

If you are subclassing a structural class, best practice is to set the defaultObjectCategory value of the new class to the same DN of the super class. This allows the standard UI to "find" your subclass.

The following code fragment shows how to get the DN of the Organizational-Unit object class, which you could then use to specify the defaultObjectCategory value of a new class that is a subclass of Organizational-Unit.

//Get the DN for organizationalUnit class to use for the default category.
//m_pSchema is an IADsContainer pointer to the Schema container.
LPOLESTR szDefaultCategory = new OLECHAR[MAX_PATH];
if (m_pSchema)
{
    VARIANT varDN;
    VariantInit(&varDN);
    IDispatch *pDisp = NULL;
    IADs *pObject = NULL;
    //Want ou as the default category
    hr = m_pSchema->GetObject(L"classSchema",L"cn=Organizational-Unit",&pDisp);
    if (SUCCEEDED(hr))
    {
        hr = pDisp->QueryInterface(IID_IADs,(void **)&pObject);
        if (SUCCEEDED(hr))
        {
            hr = pObject->Get(L"distinguishedName",&varDN);
            if (SUCCEEDED(hr))
            {
                wcscpy(szDefaultCategory, varDN.bstrVal);
            }
        }
        if (pObject)
            pObject->Release();
    }
    if (pDisp)
        pDisp->Release();
}