Platform SDK: Active Directory, ADSI, and Directory Services |
The following functions create an attributeSchema object in the ADSI cache.
The CreateAttribute function creates the attributeSchema object. Note that the IADs::SetInfo must be called in order to commit the new attributeSchema object to the directory.
The BytesToVariantArray function is a utility function that packs an octet string into a variant array.
//Create an attribute with IADsContainer::Create. There is caching. //This function creates the attributeSchema object but does not commit it. //It is up to the caller to call IADs::SetInfo on the new attribute object //and commit it to the ds. HRESULT CreateAttribute( IADsContainer *pSchema, //IADsContainer to schema container. LPOLESTR szAttributeName, LPOLESTR szLDAPDisplayName,// LPOLESTR szAttributeOID, const GUID * pSchemaIDGUID,// LPOLESTR szAttributeSyntax, int iOmSyntax, PBYTE pbomObjectClass, DWORD dwSizeomObjectClass, //size of pbomObjectClass. LPOLESTR szDescription, BOOL bIsSingleValued, BOOL bIsInGC, BOOL bIsIndexed, int iLowerRange,// int iUpperRange,// int iLinkID,// LPOLESTR szAdminDisplayName,// IADs **ppNewAttribute //Return an IADs pointer to the new attribute. ) { if ((!szAttributeName) ||(!szAttributeOID) ||(!szAttributeSyntax) ||(!iOmSyntax) ||(!szAttributeSyntax) ) return E_INVALIDARG; if (!ppNewAttribute) 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,szAttributeName); (*ppNewAttribute) = NULL; VARIANT var; if (!pSchema) return E_POINTER; hr = pSchema->Create(L"attributeSchema",szBuffer,&pDisp); if (SUCCEEDED(hr)) { hr = pDisp->QueryInterface(IID_IADs, (void**)ppNewAttribute); 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(szAttributeName); hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put lDAPDisplayName. //If NULL, let it default (that is, don't set it). if (szLDAPDisplayName) { szAttributeToSet = L"lDAPDisplayName"; var.vt = VT_BSTR; var.bstrVal = SysAllocString(szLDAPDisplayName); hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; } //Put attributeID szAttributeToSet = L"attributeID"; var.vt = VT_BSTR; var.bstrVal = SysAllocString(szAttributeOID); hrPut = (*ppNewAttribute)->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 = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); } hr = hrPut; } //Put attributeSyntax szAttributeToSet = L"attributeSyntax"; var.vt = VT_BSTR; var.bstrVal = SysAllocString(szAttributeSyntax); hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put oMSyntax szAttributeToSet = L"oMSyntax"; var.vt = VT_I4; var.lVal = iOmSyntax; hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put searchFlags szAttributeToSet = L"searchFlags"; var.vt = VT_I4; if (bIsIndexed) var.lVal = 1; else var.lVal = 0; hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put isSingleValued szAttributeToSet = L"isSingleValued"; var.vt = VT_BOOL; if (bIsSingleValued) var.boolVal = VARIANT_TRUE; else var.boolVal = VARIANT_FALSE; hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put isMemberOfPartialAttributeSet szAttributeToSet = L"isMemberOfPartialAttributeSet"; var.vt = VT_BOOL; if (bIsInGC) var.boolVal = VARIANT_TRUE; else var.boolVal = VARIANT_FALSE; hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put description szAttributeToSet = L"description"; var.vt = VT_BSTR; var.bstrVal = SysAllocString(szDescription); hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put rangeLower and rangeUpper //If both are 0, let them default (ie, don't set them). if ((iLowerRange>=0)&&(iUpperRange>0)) { //Make sure they are legal values if (iLowerRange < iUpperRange) { //Set rangeUpper szAttributeToSet = L"rangeUpper"; var.vt = VT_I4; var.lVal = iUpperRange; hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); if (SUCCEEDED(hrPut)) { //Set rangeLower szAttributeToSet = L"rangeLower"; var.vt = VT_I4; var.lVal = iLowerRange; hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); } hr = hrPut; } else hr = E_INVALIDARG; } //Put linkID. If linkID is 0, let it default (ie, don't set it). if (iLinkID>0) { szAttributeToSet = L"linkID"; var.vt = VT_I4; var.lVal = iLinkID; hrPut = (*ppNewAttribute)->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(szAttributeName); } else { var.bstrVal = SysAllocString(szAdminDisplayName); } hrPut = (*ppNewAttribute)->Put(szAttributeToSet,var); VariantClear(&var); hr = hrPut; //Put omObjectClass //Should only set this if it is going to be used to disambiguate omSyntax 127 attributes. if (pbomObjectClass && dwSizeomObjectClass) { hrPut = BytesToVariantArray( pbomObjectClass, //Pointer to bytes to put in a variant array. dwSizeomObjectClass,//Size of pValue in bytes. &var //Return variant containing octet string (VT_UI1|VT_ARRAY). ); if (SUCCEEDED(hrPut)) { szAttributeToSet = L"omObjectClass"; hrPut = (*ppNewAttribute)->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 (*ppNewAttribute) { (*ppNewAttribute)->Release(); (*ppNewAttribute) = NULL; } } return hr; } 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; }