| 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;
}