Platform SDK: Active Directory, ADSI, and Directory Services

Example Code for Finding the Next linkID

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