Directory Services

Accessing Attributes With the IDirectoryObject Interface

The IDirectoryObject interface provides a client application written in C and C++ with direct access to directory service objects. The interface enables access by means of a direct network protocol, rather than through the ADSI property cache. In place of the properties supported by the IADs interface, IDirectoryObject provides methods that support a critical subset of an object's maintenance methods and provide access to its attributes. With IDirectoryObject, a client can get or set any number of object attributes with one method call. Unlike the corresponding Automation methods, which are batched, those of IDirectoryObject are executed when called. Because methods on this interface do not require creating an instance of an Automation directory object, the performance overhead is low.

Clients written in languages such as C and C++ should use the methods of the IDirectoryObject interface to optimize performance and take advantage of native directory service interfaces. Automation clients cannot use IDirectoryObject. Instead, they should use the IADs interface.

The IDirectoryObject::GetObjectAttributes method retrieves attributes with both single and multiple values. This method takes a list of requested attributes and returns an ADS_ATTR_INFO structure. ADSI allocates this structure, so it must be freed when it is no longer required using the FreeADsMem function.

The order of returned attribute values is not necessarily the same as the order in which the attributes were requested. Therefore, it is necessary to compare the attribute names returned from ADSI.

Note  The ADS_ATTR_INFO structure does not return all of the attributes requested. Only those attributes that contain values are part of the returned structure.

The number of attributes returned is determined by the dwNumberAttributes parameter passed to the IDirectoryObject::GetObjectAttributes method.

The following code example binds to an object and uses the IDirectoryObject::GetObjectAttributes method to retrieve attributes of the object.

HRESULT hr;
IDirectoryObject *pDirObject;

CoInitialize(NULL);

hr = ADsGetObject(  L"LDAP://CN=Jeff Smith,OU=Users,DC=Fabrikam,DC=com",
					IID_IDirectoryObject, 
					(void**)&pDirObject);

if(SUCCEEDED(hr))
{
	ADS_ATTR_INFO *pAttrInfo = NULL;
	LPWSTR pAttrNames[] = {L"cn", L"title", L"otherTelephone"};
	DWORD dwNumAttr = sizeof(pAttrNames)/sizeof(LPWSTR);
	DWORD dwReturn;

	//////////////////////////////////////////////////
	// Get attribute values requested.
	// Be aware that the order is not necessarily the 
	// same as requested using pAttrNames.
	//////////////////////////////////////////////////
	hr = pDirObject->GetObjectAttributes(pAttrNames, 
										 dwNumAttr, 
										 &pAttrInfo, 
										 &dwReturn);
	 
	if(SUCCEEDED(hr))
	{
		for(DWORD idx = 0; idx < dwReturn; idx++)
		{
			if(_wcsicmp(pAttrInfo[idx].pszAttrName, L"cn") == 0)
			{
				if(pAttrInfo[idx].dwADsType == ADSTYPE_CASE_IGNORE_STRING)
				{
					wprintf(L"Common Name: %s\n", pAttrInfo[idx].pADsValues[0].CaseIgnoreString);
			}
		}
			else if(_wcsicmp(pAttrInfo[idx].pszAttrName, L"title") == 0)
			{
				if(pAttrInfo->dwADsType == ADSTYPE_CASE_IGNORE_STRING)
				{
					wprintf(L"Title: %s\n", pAttrInfo[idx].pADsValues[0].CaseIgnoreString);
			}
		}
			else if(_wcsicmp(pAttrInfo[idx].pszAttrName, L"otherTelephone") == 0)
			{   
				// Print out multi-valued property, "Other Telephones".
				if(pAttrInfo[idx].dwADsType == ADSTYPE_CASE_IGNORE_STRING)
				{
					wprintf(L"Other Telephones:");
					for(DWORD val = 0; val < pAttrInfo[idx].dwNumValues; val++) 
					{
						wprintf(L"  %s\n", pAttrInfo[idx].pADsValues[val].CaseIgnoreString);
				}
			}
		}
	}

		FreeADsMem(pAttrInfo);
}
	 
	pDirObject->Release();
}

CoUninitialize();