Platform SDK: Active Directory, ADSI, and Directory Services

Example Code for Detecting Schema Naming Collisions

The following C/C++ function queries the schema for the key naming attributes on a classSchema or attributeSchema object.

It returns TRUE if conflicting attributes or classes are found.

It returns FALSE if the attribute or class with the specified cn, lDAPDisplayName, OID, schemaIDGUID, or linkID does not conflict with the schema and, therefore, is safe to add to the schema.

HRESULT FindCollidingAttributesOrClasses(IDirectorySearch *pSchemaNC, //IDirectorySearch pointer to schema naming context.
    LPOLESTR szName,
    LPOLESTR szLDAPDisplayName,
    LPOLESTR szOID,
    const GUID * pSchemaIDGUID,
    DWORD dwLinkID, //Set 0L if attribute is not linked or if checking for class.
    BOOL *pbIsColliding//Return result.
              )
{
if (
    (!pSchemaNC)
  ||(!szName)
  ||(!szLDAPDisplayName)
  ||(!szOID)
  ||(!pSchemaIDGUID)
   )
  return E_POINTER;
 
LPOLESTR szFilter = new OLECHAR(MAX_PATH*5);
LPOLESTR szBuffer = NULL;
 
HRESULT hr = E_FAIL;
 
hr = ADsEncodeBinaryData((LPBYTE)pSchemaIDGUID,sizeof(GUID),&szBuffer);
if (SUCCEEDED(hr))
{
    if (dwLinkID>0L)
      swprintf(szFilter,L"(|(cn=%s)(lDAPDisplayName=%s)(attributeID=%s)(governsID=%s)(schemaIDGUID=%s)(linkID=%d))",szName,szLDAPDisplayName,szOID,szOID,szBuffer,dwLinkID);
    else
      swprintf(szFilter,L"(|(cn=%s)(lDAPDisplayName=%s)(attributeID=%s)(governsID=%s)(schemaIDGUID=%s))",szName,szLDAPDisplayName,szOID,szOID,szBuffer);
    //Attributes are one-level deep in the Schema container so only need to search one level.
  ADS_SEARCHPREF_INFO SearchPrefs;
  SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
  SearchPrefs.vValue.Integer = ADS_SCOPE_ONELEVEL;
    DWORD dwNumPrefs = 1;
 
  // COL for iterations
  LPOLESTR pszColumn = NULL;    
  ADS_SEARCH_COLUMN col;
 
    // Handle used for searching
    ADS_SEARCH_HANDLE hSearch = NULL;
 
    int iCount = 0;
  
 
  // Set the search preference
    hr = pSchemaNC->SetSearchPreference( &SearchPrefs, dwNumPrefs);
    if (SUCCEEDED(hr))
  {
    LPOLESTR pszNonVerboseList[] = {L"lDAPDisplayName",L"cn",L"attributeID",L"governsID",L"schemaIDGUID",L"linkID",L"objectCategory"};
 
    DWORD x = 0L;
 
    hr = pSchemaNC->ExecuteSearch(szFilter,
                    pszNonVerboseList,
                    sizeof(pszNonVerboseList)/sizeof(LPOLESTR),
                    &hSearch
                    );
     if ( SUCCEEDED(hr) )
    {    
    // Call IDirectorySearch::GetNextRow() to retrieve the next row 
    //of data
      hr = pSchemaNC->GetFirstRow( hSearch);
      if (SUCCEEDED(hr))
      {
      while( hr != S_ADS_NOMORE_ROWS )
      {
        //Keep track of count.
        iCount++;
          //Get the next row
         hr = pSchemaNC->GetNextRow( hSearch);
      }
 
      }
      // Close the search handle to clean up
      pSchemaNC->CloseSearchHandle(hSearch);
    }
  }
  if (SUCCEEDED(hr))
  {
    if (iCount==0)
    {
      *pbIsColliding = FALSE;
      hr = S_FALSE;
    }
    else if (iCount>0)
    {
      *pbIsColliding = TRUE;
      hr = S_OK;
    }
    else
      hr = E_FAIL;
  }
}
if(szBuffer)
  FreeADsMem(szBuffer);
    return hr;
}