| Platform SDK: Active Directory, ADSI, and Directory Services |
The following C++ function finds the largest link ID and returns the next forward link value to use when creating a pair of linked attributes.
//Finds the largest link ID and returns the next forward link value to use.
HRESULT GetNextLinkID(IDirectorySearch *pSchemaNC, //IDirectorySearch pointer to schema naming context.
int *iNextLinkID
)
{
if (!pSchemaNC)
return E_POINTER;
//Create search filter
//Find attributes that have a linkID set.
LPOLESTR pszSearchFilter = L"(&(objectCategory=attributeSchema)(linkID=*))";
//Create search preferences
const DWORD dwNumPrefs = 2;
ADS_SEARCHPREF_INFO SearchPrefs[dwNumPrefs];
//Attribute and classes are one-level deep in the Schema container so only need to search one level.
SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
//Sort order
//Sort against linkID and sort from highest to lowest value.
ADS_SORTKEY sortkey[] = { {L"linkID",NULL,FALSE} };
//Not used set to NULL
SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_SORT_ON;
SearchPrefs[1].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
SearchPrefs[1].vValue.ProviderSpecific.dwLength = sizeof(sortkey);
SearchPrefs[1].vValue.ProviderSpecific.lpValue = (LPBYTE)(sortkey);
// COL for iterations
LPOLESTR pszColumn = NULL;
ADS_SEARCH_COLUMN col;
HRESULT hr;
// Interface Pointers
IADs *pObj = NULL;
IADs * pIADs = NULL;
// Handle used for searching
ADS_SEARCH_HANDLE hSearch = NULL;
// Set the search preference
hr = pSchemaNC->SetSearchPreference( SearchPrefs, dwNumPrefs);
if (FAILED(hr))
return hr;
LPOLESTR pszReturnedPropertiesList[] = {L"linkID"};
int iCount = 0;
DWORD x = 0L;
//Set largest value to 0
int iHighestLinkID = 0;
//Return non-verbose list properties only
hr = pSchemaNC->ExecuteSearch(pszSearchFilter,
pszReturnedPropertiesList,
sizeof(pszReturnedPropertiesList)/sizeof(LPOLESTR),
&hSearch
);
if ( SUCCEEDED(hr) )
{
// Call IDirectorySearch::GetFirstRow() to start the search.
hr = pSchemaNC->GetFirstRow( hSearch);
if (SUCCEEDED(hr))
{
while( hr != S_ADS_NOMORE_ROWS )
{
//Keep track of count.
iCount++;
// loop through the array of passed column names,
while( pSchemaNC->GetNextColumnName( hSearch, &pszColumn ) != S_ADS_NOMORE_COLUMNS )
{
hr = pSchemaNC->GetColumn( hSearch, pszColumn, &col );
if ( SUCCEEDED(hr) )
{
if (ADSTYPE_INTEGER==col.dwADsType)
{
if (col.pADsValues[x].Integer > iHighestLinkID)
iHighestLinkID = col.pADsValues[x].Integer;
}
pSchemaNC->FreeColumn( &col );
}
FreeADsMem( pszColumn );
}
//Get the next row
hr = pSchemaNC->GetNextRow( hSearch);
}
}
// Close the search handle to clean up
pSchemaNC->CloseSearchHandle(hSearch);
}
if (SUCCEEDED(hr) && iCount>0)
{
DWORD dwIsOdd;
(*iNextLinkID) = iHighestLinkID;
//See if highest link value is divisible by zero.
dwIsOdd = iHighestLinkID%2;
//Regardless of even or odd, need to increment once.
(*iNextLinkID)++;
//If there is a remainder, value is odd so no need to increment again.
//If there is no remainder, the value is even
//so increment next link value again to the next even value.
if (!dwIsOdd)
(*iNextLinkID)++;
hr = S_OK;
}
else
{
//Search succeeded but could not find any attributes.
//Should never hit this.
(*iNextLinkID) = 0;
hr = S_FALSE;
}
return hr;
}