Example Code for Creating an Attribute
The following code example creates an attributeSchema object in the schema container.
The CreateAttribute function creates an attributeSchema object in the schema container, but does not commit it to the directory. Call the IADs.SetInfo method 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.
/********************************************************************
BytesToVariantArray()
Converts an arrya of BYTEs into a VARIANT array.
Parameters:
pValue = Contains an array of BYTES to convert. cValueElements
contains the number of elements in this array.
cValueElements - Contains the number of elements in the pValue
array.
pVariant - Receives the VARIANT that contains an octet string
(VT_UI1 | VT_ARRAY)
*********************************************************************/
HRESULT BytesToVariantArray(
PBYTE pValue,
ULONG cValueElements,
VARIANT *pVariant
)
{
HRESULT hr = E_FAIL;
SAFEARRAY *pArrayVal = NULL;
SAFEARRAYBOUND arrayBound;
CHAR HUGEP *pArray = NULL;
// Check parameters.
if((NULL == pValue) || !(cValueElements > 0))
{
return E_INVALIDARG;
}
// 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 (!(NULL == pArrayVal))
{
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
{
// Cleanup if the array cannot be accessed.
if (pArrayVal)
{
SafeArrayDestroy(pArrayVal);
}
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
/*******************************************************************
CreateAttribute()
Creates a new attribute in the schema container
IADsContainer.Create.
This function creates the attributeSchema object, but does not
commit it to the directory. The caller must call IADs.SetInfo
on the new attribute object to commit it to the directory.
Parameters:
pwszAttributeName - Contains a null-terminated string that
contains the name of the attribute.
pwszLDAPDisplayName - Contains a null-terminated string that
contains the lDAPDisplayName of the attribute.
pwszAttributeOID - Contains a null-terminated string that
contains the OID of the attribute.
pSchemaIDGUID -
pwszAttributeSyntax - Contains a null-terminated string that
contains the syntax of the attribute.
iOmSyntax - Contains the value for the oMSyntax attribute.
pbomObjectClass - Pointer to a BYTE array that contains the
value for the oMObjectClass attribute. dwSizeomObjectClass
contains the number of elements in this array.
dwSizeomObjectClass - Contains the number of elements in the
pbomObjectClass array.
pwszDescription - Contains a null-terminated string that
contains the description of the attribute.
fIsSingleValued - Contains TRUE if the attribute is
single-valued or FALSE if the attribute is multi-valued.
fIsInGC - Contains TRUE if the attribute is contained in the
global catalog or FALSE if the attribute should not be
contained in the global catalog.
fIsIndexed - Contains TRUE if the attribute is indexed or
FALSE if the attribute is not indexed.
iLowerRange - Contains the lower range of the attribute value.
Contains zero if the range should not be set.
iUpperRange - Contains the upper range of the attribute value.
Contains zero if the range should not be set.
iLinkID - Contains the value for the linkID attribute. If this
cotnains zero, the linkID attribute is not set.
pwszAdminDisplayName - Contains a null-terminated string that
contains the admin display name of the attribute.
ppadsNewAttribute - Receives a pointer to the IADs interface of
the attribute object created.
********************************************************************/
HRESULT CreateAttribute(
LPCWSTR pwszAttributeName,
LPCWSTR pwszLDAPDisplayName,
LPCWSTR pwszAttributeOID,
const GUID * pSchemaIDGUID,
LPCWSTR pwszAttributeSyntax,
int iOmSyntax,
PBYTE pbomObjectClass,
DWORD dwSizeomObjectClass,
LPCWSTR pwszDescription,
BOOL fIsSingleValued,
BOOL fIsInGC,
BOOL fIsIndexed,
int iLowerRange,
int iUpperRange,
int iLinkID,
LPCWSTR pwszAdminDisplayName,
IADs **ppadsNewAttribute
)
{
if(!ppadsNewAttribute)
{
return E_POINTER;
}
*ppadsNewAttribute = NULL;
if( (!pwszAttributeName) ||
(!pwszAttributeOID) ||
(!pwszAttributeSyntax) ||
(!iOmSyntax)
)
{
return E_INVALIDARG;
}
if(iLowerRange < iUpperRange)
{
return E_INVALIDARG;
}
HRESULT hr;
CComPtr<IADs> spRoot;
hr = ADsGetObject(L"LDAP://RootDSE",
IID_IADs,
(void**)&spRoot);
if(FAILED(hr))
{
return hr;
}
CComVariant svarSchema;
// Get the disintguished name of the schema container.
hr = spRoot->Get(CComBSTR("schemaNamingContext"), &svarSchema);
if(FAILED(hr))
{
return hr;
}
// Bind to the IADsContainer interface of the schema container.
CComPtr<IADsContainer> spSchemaCont;
hr = ADsOpenObject( L"LDAP://RootDSE",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)&spSchemaCont);
if(FAILED(hr))
{
return hr;
}
CComPtr<IDispatch> spDisp;
CComBSTR sbstrAttribute = "CN=";
sbstrAttribute += pwszAttributeName;
// Create the object in the schema container.
hr = spSchemaCont->Create(CComBSTR("attributeSchema"),
sbstrAttribute,
&spDisp);
CComPtr<IADs> spNewAttribute;
hr = spDisp->QueryInterface(IID_IADs, (void**)&spNewAttribute);
if(FAILED(hr))
{
return hr;
}
CComBSTR sbstrAttributeToSet;
CComVariant svar;
// Put this value so that it can be read from the cache.
sbstrAttributeToSet = "cn";
svar = pwszAttributeName;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put lDAPDisplayName.
// If NULL, let it default; that is, do not set it.
if (pwszLDAPDisplayName)
{
sbstrAttributeToSet = "lDAPDisplayName";
svar = pwszLDAPDisplayName;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
}
// Put attributeID.
sbstrAttributeToSet = "attributeID";
svar = pwszAttributeOID;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put schemaIDGUID.
// If NULL, let it default; that is, do not set it.
if (pSchemaIDGUID)
{
hr = BytesToVariantArray(
(LPBYTE)pSchemaIDGUID,
sizeof(GUID),
&svar
);
if(FAILED(hr))
{
return hr;
}
sbstrAttributeToSet = "schemaIDGUID";
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
}
// Put attributeSyntax.
sbstrAttributeToSet = "attributeSyntax";
svar = pwszAttributeSyntax;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put oMSyntax.
sbstrAttributeToSet = "oMSyntax";
svar = iOmSyntax;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put searchFlags.
sbstrAttributeToSet = "searchFlags";
if (fIsIndexed)
{
svar = 1;
}
else
{
svar = 0;
}
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put isSingleValued.
sbstrAttributeToSet = "isSingleValued";
if (fIsSingleValued)
{
svar = VARIANT_TRUE;
}
else
{
svar = VARIANT_FALSE;
}
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put isMemberOfPartialAttributeSet.
sbstrAttributeToSet = "isMemberOfPartialAttributeSet";
if (fIsInGC)
{
svar = VARIANT_TRUE;
}
else
{
svar = VARIANT_FALSE;
}
svar.vt = VT_BOOL;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put description.
sbstrAttributeToSet = "description";
svar = pwszDescription;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put rangeLower and rangeUpper.
// If both are 0, let them default; that is do not set them.
if ((iLowerRange >= 0) && (iUpperRange > 0))
{
// Set rangeUpper.
sbstrAttributeToSet = "rangeUpper";
svar = iUpperRange;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Set rangeLower.
sbstrAttributeToSet = "rangeLower";
svar = iLowerRange;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
}
// Put linkID. If linkID is 0, let it default; that
// is, do not set it.
if (iLinkID>0)
{
sbstrAttributeToSet = "linkID";
svar = iLinkID;
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
}
// Put adminDisplayName.
// If NULL, set it to the same string as cn.
sbstrAttributeToSet = "adminDisplayName";
if (!pwszAdminDisplayName)
{
svar = pwszAttributeName;
}
else
{
svar = pwszAdminDisplayName;
}
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
// Put omObjectClass.
// Only set this if used to delineate omSyntax 127 attributes.
if (pbomObjectClass && dwSizeomObjectClass)
{
hr = BytesToVariantArray(
pbomObjectClass,
dwSizeomObjectClass,
&svar
);
if(FAILED(hr))
{
return hr;
}
sbstrAttributeToSet = "omObjectClass";
hr = spNewAttribute->Put(sbstrAttributeToSet, svar);
if(FAILED(hr))
{
return hr;
}
}
// Get a copy of the interface to return.
hr = spNewAttribute->QueryInterface(IID_IADs,
(LPVOID*)ppadsNewAttribute);
return hr;
}
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for