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