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.

/***************************************************************************

	FindCollidingAttributesOrClasses()

***************************************************************************/

HRESULT FindCollidingAttributesOrClasses(
	IDirectorySearch *pSchemaNC, //IDirectorySearch pointer to schema naming context.
	LPWSTR szName,
	LPWSTR szLDAPDisplayName,
	LPWSTR szOID,
	const GUID * pSchemaIDGUID,
	DWORD dwLinkID, //0 if attribute is not linked or if checking for class.
	BOOL *pfIsColliding)
{
	if (!pSchemaNC || !szName || !szLDAPDisplayName || !szOID || !pSchemaIDGUID)
	{
		return E_POINTER;
}
 
	HRESULT hr = E_FAIL;
	
	LPWSTR szBuffer = NULL;
	
	hr = ADsEncodeBinaryData((LPBYTE)pSchemaIDGUID, sizeof(GUID), &szBuffer);
	if (SUCCEEDED(hr))
	{
		LPWSTR pwszFormatLinkID = L"(|(cn=%s)(lDAPDisplayName=%s)(attributeID=%s)(governsID=%s)(schemaIDGUID=%s)(linkID=%d))";
		LPWSTR pwszFormatNoLinkID = L"(|(cn=%s)(lDAPDisplayName=%s)(attributeID=%s)(governsID=%s)(schemaIDGUID=%s))";
		LPWSTR szFilter = new WCHAR[lstrlenW(pwszFormatLinkID) + 
			lstrlenW(szName) + 
			lstrlenW(szLDAPDisplayName) + 
			lstrlenW(szOID) + 
			lstrlenW(szOID) +
			lstrlenW(szBuffer) +
			20 +
			1];

		if(szFilter)
		{
			if (dwLinkID > 0L)
			{
				swprintf(szFilter,
					pwszFormatLinkID,
					szName,
					szLDAPDisplayName,
					szOID,
					szOID,
					szBuffer,
					dwLinkID);
		}
			else
			{
				swprintf(szFilter,
					pwszFormatNoLinkID,
					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[2];
			SearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
			SearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
			SearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL;

			SearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
			SearchPrefs[1].vValue.dwType = ADSTYPE_INTEGER;
			SearchPrefs[1].vValue.Integer = 1000;
		
			int iCount = 0;
		
			// Set the search preference
			hr = pSchemaNC->SetSearchPreference(SearchPrefs, sizeof(SearchPrefs)/sizeof(ADS_SEARCHPREF_INFO));
			if (SUCCEEDED(hr))
			{
				LPWSTR pszAttribs[] = {
					L"lDAPDisplayName", 
					L"cn", 
					L"attributeID", 
					L"governsID", 
					L"schemaIDGUID", 
					L"linkID", 
					L"objectCategory"
			};

				// Handle used for searching
				ADS_SEARCH_HANDLE hSearch = NULL;
				DWORD x = 0L;
			
				hr = pSchemaNC->ExecuteSearch(szFilter,
								pszAttribs,
								sizeof(pszAttribs)/sizeof(LPWSTR),
								&hSearch);
				if (SUCCEEDED(hr))
				{
					// Call IDirectorySearch::GetNextRow() to retrieve the next row 
					//of data
					hr = pSchemaNC->GetFirstRow(hSearch);
					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 (0 == iCount)
						{
							*pfIsColliding = FALSE;
					}
						else
						{
							*pfIsColliding = TRUE;
					}

						hr = S_OK;
				}
			}
		}

			delete szFilter;
	}
		
		FreeADsMem(szBuffer);
}

	return hr;
}