Platform SDK: Active Directory, ADSI, and Directory Services

Example code for Creating a Class

The following C/C++ example creates a classSchema object in the ADSI cache. Note that the

The sample CreateClass routine creates the classSchema object and returns an IADs pointer to the new object. Note that CreateClass does not call IADs::SetInfo to commit the new classSchema object to the directory. It is up to the caller to do that using the returned pointer.

The BytesToVariantArray routine is a utility function that packs an octet string into a variant array.

////////////////////////////////////////////////////////// 
// CreateClass routine
// Calls IADsContainer::Create to create a new classSchema object in
// the schema container. Sets key properties of the new class.
// Note that the CreateClass routine does NOT commit the new class
// to the directory. It is up to the CreateClass caller to actually 
// commit the new class by calling IADs::SetInfo on the returned 
// pointer to the new class object
////////////////////////////////////////////////////////// 
HRESULT CreateClass(
    IADsContainer *pSchema,
    LPOLESTR szClassName,
    LPOLESTR szLDAPDisplayName,//
    LPOLESTR szClassOID,
    const GUID * pSchemaIDGUID,//
    LPOLESTR szSubClassOf,
    LPOLESTR *arrayAuxiliaryClasses,
    DWORD dwSizearrayAuxiliaryClasses,
    LPOLESTR szDefaultObjectCategory,
    LPOLESTR szDescription,
    BOOL bDefaultHidingValue,
    LPOLESTR szDefaultSecurityDescriptor,
    LPOLESTR szRDNAttribute,//
    int iObjectClassCategory,//
    LPOLESTR *arrayPossibleSuperiors,
    DWORD dwSizearrayPossibleSuperiors,
    LPOLESTR *arrayMustContain,
    DWORD dwSizearrayMustContain,
    LPOLESTR *arrayMayContain,
        DWORD dwSizearrayMayContain,
    LPOLESTR szAdminDisplayName,//
    IADs **ppNewClass //Return an IADs pointer to the new class.
    )
{
if ((!szClassName)
    ||(!szClassOID)
    ||(!szSubClassOf)
    ||(!iObjectClassCategory)
    ||(!arrayPossibleSuperiors)
   )
  return E_INVALIDARG;
if (!ppNewClass)
  return E_POINTER;
HRESULT hr = E_FAIL;
HRESULT hrPut = S_OK;
IDispatch *pDisp = NULL;
LPOLESTR szBuffer = new OLECHAR[MAX_PATH*2];
LPOLESTR szAttributeToSet = NULL;
wcscpy(szBuffer,L"cn=");
wcscat(szBuffer,szClassName);
(*ppNewClass) = NULL;
VARIANT var;
if (!pSchema)
  return E_POINTER;
hr = pSchema->Create(L"classSchema",szBuffer,&pDisp);
if (SUCCEEDED(hr))
{
  hr = pDisp->QueryInterface(IID_IADs, (void**)ppNewClass);
  while (SUCCEEDED(hr))
  {
    //Put cn Put this value so that it can be read from the cache.
    szAttributeToSet = L"cn";
    var.vt = VT_BSTR;
    var.bstrVal = SysAllocString(szClassName);
    hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
    VariantClear(&var);
    hr = hrPut;
 
    //Put lDAPDisplayName.
    //If NULL, let it default (ie, don't set it).
    if (szLDAPDisplayName)
    {
      szAttributeToSet = L"lDAPDisplayName";
      var.vt = VT_BSTR;
      var.bstrVal = SysAllocString(szLDAPDisplayName);
      hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
      VariantClear(&var);
      hr = hrPut;
    }
 
    //Put attributeID
    szAttributeToSet = L"governsID";
    var.vt = VT_BSTR;
    var.bstrVal = SysAllocString(szClassOID);
    hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
    VariantClear(&var);
    hr = hrPut;
 
    //Put schemaIDGUID.
    //If NULL, let it default (ie, don't set it).
    if (pSchemaIDGUID)
    {
      hrPut = BytesToVariantArray(
        (LPBYTE)pSchemaIDGUID, //Pointer to bytes to put in a variant array.
        sizeof(GUID),//Size of pValue in bytes.
        &var //Return variant containing octet string (VT_UI1|VT_ARRAY).
        );
      if (SUCCEEDED(hrPut))
      {
       szAttributeToSet = L"schemaIDGUID";
      hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
      VariantClear(&var);
      }
      hr = hrPut;
    }
 
    //Put subClassOf
    szAttributeToSet = L"subClassOf";
    var.vt = VT_BSTR;
    //TODO: Check for existence of the class.
    var.bstrVal = SysAllocString(szSubClassOf);
    hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
    VariantClear(&var);
    hr = hrPut;
 
    //Put defaultObjectCategory
    //If NULL, let it default (ie, don't set it).
    if (szDefaultObjectCategory)
    {
      szAttributeToSet = L"defaultObjectCategory";
      var.vt = VT_BSTR;
        //TODO: Check to ensure it is a valid DN.
      var.bstrVal = SysAllocString(szDefaultObjectCategory);
      hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
      VariantClear(&var);
      hr = hrPut;
    }
 
    //Put objectClassCategory
    szAttributeToSet = L"objectClassCategory";
    var.vt = VT_I4;
    var.lVal = iObjectClassCategory;
    hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
    VariantClear(&var);
    hr = hrPut;
 
    //Put defaultHidingValue
    szAttributeToSet = L"defaultHidingValue";
    var.vt = VT_BOOL;
    if (bDefaultHidingValue)
      var.boolVal = VARIANT_TRUE;
    else
      var.boolVal = VARIANT_FALSE;
    hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
    VariantClear(&var);
    hr = hrPut;
 
    //Put RDNAttrID
    //If NULL, let it default (that is, don't set it).
    if (szRDNAttribute)
    {
      szAttributeToSet = L"rDNAttID";
      var.vt = VT_BSTR;
        //TODO: Check to ensure it is a valid attribute.
      var.bstrVal = SysAllocString(szRDNAttribute);
      hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
      VariantClear(&var);
      hr = hrPut;
    }
 
    //Put defaultSecurityDescriptor
    //If NULL, let it default (ie, don't set it).
    if (szDefaultSecurityDescriptor)
    {
      szAttributeToSet = L"defaultSecurityDescriptor";
      var.vt = VT_BSTR;
      var.bstrVal = SysAllocString(szDefaultSecurityDescriptor);
      hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
      VariantClear(&var);
      hr = hrPut;
    }
 
    if (arrayPossibleSuperiors && dwSizearrayPossibleSuperiors)
    {
      // Build a Variant of array type, using the specified string array.
      hr = ADsBuildVarArrayStr(arrayPossibleSuperiors, dwSizearrayPossibleSuperiors, &var);
      if (SUCCEEDED(hr))
      {
        szAttributeToSet = L"possSuperiors";
            //TODO: Check to ensure that all the specified classes are valid.
        hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
        VariantClear(&var);
        hr = hrPut;
      }
    }
 
    if (arrayMustContain && dwSizearrayMustContain)
    {
      // Build a Variant of array type, using the specified string array.
      hr = ADsBuildVarArrayStr(arrayMustContain, dwSizearrayMustContain, &var);
      if (SUCCEEDED(hr))
      {
        szAttributeToSet = L"mustContain";
            //TODO: Check to ensure that all the specified attributes are valid.
        hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
        VariantClear(&var);
        hr = hrPut;
      }
    }
 
    if (arrayMayContain && dwSizearrayMayContain)
    {
      // Build a Variant of array type, using the specified string array.
      hr = ADsBuildVarArrayStr(arrayMayContain, dwSizearrayMayContain, &var);
      if (SUCCEEDED(hr))
      {
        szAttributeToSet = L"mayContain";
            //TODO: Check to ensure that all the specified attributes are valid.
        hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
        VariantClear(&var);
        hr = hrPut;
      }
    }
 
    if (arrayAuxiliaryClasses && dwSizearrayAuxiliaryClasses)
    {
      // Build a Variant of array type, using the specified string array.
      hr = ADsBuildVarArrayStr(arrayAuxiliaryClasses, dwSizearrayAuxiliaryClasses, &var);
      if (SUCCEEDED(hr))
      {
        szAttributeToSet = L"auxiliaryClass";
            //TODO: Check to ensure that all the specified classes are valid.
        hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
        VariantClear(&var);
        hr = hrPut;
      }
    }
 
 
    //Put description
    szAttributeToSet = L"description";
    var.vt = VT_BSTR;
    var.bstrVal = SysAllocString(szDescription);
    hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
    VariantClear(&var);
    hr = hrPut;
 
 
    //Put adminDisplayName.
    //If NULL, set it to the same string as cn.
 
      szAttributeToSet = L"adminDisplayName";
      var.vt = VT_BSTR;
      if (!szAdminDisplayName)
      {
        var.bstrVal = SysAllocString(szClassName);
      }
      else
      {
        var.bstrVal = SysAllocString(szAdminDisplayName);
      }
      hrPut = (*ppNewClass)->Put(szAttributeToSet,var);
      VariantClear(&var);
      hr = hrPut;
 
 
    //End of properties to set.
    break;
  }
}
if (pDisp)
  pDisp->Release();
 
if (FAILED(hr))
{
  //Clean up if failed.
  if (*ppNewClass)
  {
    (*ppNewClass)->Release();
    (*ppNewClass) = NULL;
  }
    
}
 
return hr;
}

////////////////////////////////////////////////////////// 
// BytesToVariantArray
// Packs an octet string into a variant array.
////////////////////////////////////////////////////////// 
HRESULT BytesToVariantArray(
    PBYTE pValue, //Pointer to bytes to put in a variant array.
  ULONG cValueElements,//Size of pValue in bytes.
    VARIANT *pVariant //Return variant containing octet string (VT_UI1|VT_ARRAY).
    )
{
    HRESULT hr = E_FAIL;
    SAFEARRAY *pArrayVal = NULL;
    SAFEARRAYBOUND arrayBound;
    CHAR HUGEP *pArray = NULL;
 
  //Set bound for array
    arrayBound.lLbound = 0;
    arrayBound.cElements = cValueElements;
 
    //Create the safe array for the octet string. unsigned char elements;single dimension;aBound size.
  pArrayVal = SafeArrayCreate( VT_UI1, 1, &arrayBound );
 
    if (!(pArrayVal == NULL) )
    {
        hr = SafeArrayAccessData(pArrayVal, (void HUGEP * FAR *) &pArray );
    if (SUCCEEDED(hr))
    {
      //Copy the bytes to the safe array.
            memcpy( pArray, pValue, arrayBound.cElements );
            SafeArrayUnaccessData( pArrayVal );
      //Set type to array of unsigned char
        V_VT(pVariant) = VT_ARRAY | VT_UI1;
      //Assign the safe array to the array member.
            V_ARRAY(pVariant) = pArrayVal;
      hr = S_OK;
    }
    else
    {
      //Clean up if array can't be accessed.
        if ( pArrayVal )
               SafeArrayDestroy( pArrayVal );
    }
    }
  else
  {
      hr = E_OUTOFMEMORY;
  }
 
  return hr;
}