Directory Services

Container Browser

An application can use the DsBrowseForContainer function to display a dialog box that can be used to browse through the containers in Active Directory®. The dialog box displays the containers in a tree format and enables the user to navigate through the tree using the keyboard and mouse. When the user selects an item in the dialog box, the ADsPath of the container selected by the user is provided.

DsBrowseForContainer takes a pointer to a DSBROWSEINFO structure that contains data about the dialog box and returns the ADsPath of the selected item.

The pszRoot member is a pointer to a Unicode string that contains the root container of the tree. If pszRoot is NULL, the tree will contain the entire Active Directory tree.

The pszPath member receives the ADsPath of the selected object. It is possible to specify a particular container to be visible and selected when the dialog box is first displayed. This is accomplished by setting pszPath to the ADsPath of the item to be selected and setting the DSBI_EXPANDONOPEN flag in dwFlags.

The contents and behavior of the dialog box can also be controlled at runtime by implementing a BFFCallBack function. The BFFCallBack function is implemented by the application and is called when certain events occur. An application can use these events to control how the items in the dialog box are displayed as well as the actual contents of the dialog box. For example, an application can filter the items displayed in the dialog box by implementing a BFFCallBack function that can handle the DSBM_QUERYINSERT notification. When a DSBM_QUERYINSERT notification is received, use the pszADsPath member of the DSBITEM structure to determine which item is about to be inserted. If the application determines that the item should not be displayed, it can hide the item by performing the following steps.

  1. Add the DSBF_STATE flag to the dwMask member of the DSBITEM structure.
  2. Add the DSBS_HIDDEN flag to the dwStateMask member of the DSBITEM structure.
  3. Add the DSBS_HIDDEN flag to the dwState member of the DSBITEM structure.
  4. Return a non-zero value from the BFFCallBack function.

In addition to hiding certain items, an application can modify the text and icon displayed for the item by handling the DSBM_QUERYINSERT notification. For more information, see DSBITEM.

The BFFCallBack function can use the BFFM_INITIALIZED notification to obtain the handle of the dialog box. The application can use this handle to send messages, such as BFFM_ENABLEOK, to the dialog box. For more information about the messages that can be sent to the dialog box, see BFFCallBack.

The dialog box handle can also be used to gain direct access to the controls in the dialog box. DSBID_BANNER is the identifier for the static text control that the pszTitle member of the DSBROWSEINFO structure is displayed in. DSBID_CONTAINERLIST is the identifier of the tree view control used to display the tree contents. Use of these items should be avoided, if possible, to prevent future application compatibility problems.

The following code example demonstrates how to use the DsBrowseForContainer function to create the container browser dialog box and implement a BFFCallBack function. The BFFCallBack uses the DSBM_QUERYINSERT notification to change the display name for each item to the distinguished name of the item.

#include <shlobj.h>
#include <dsclient.h>
#include <atlbase.h>

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

	WideCharToLocal()
   
**************************************************************************/

int WideCharToLocal(LPTSTR pLocal, LPWSTR pWide, DWORD dwChars)
{
	*pLocal = NULL;
	size_t nWideLength = 0;
	wchar_t *pwszSubstring;

	nWideLength = wcslen(pWide);

#ifdef UNICODE
	if(nWideLength < dwChars)
	{
		wcsncpy(pLocal, pWide, dwChars);
}
	else
	{
		wcsncpy(pLocal, pWide, dwChars-1);
		pLocal[dwChars-1] = NULL;
}
#else
	if(nWideLength < dwChars)
	{
		WideCharToMultiByte(	CP_ACP, 
								0, 
								pWide, 
								-1, 
								pLocal, 
								dwChars, 
								NULL, 
								NULL);
}
	else
	{
		pwszSubstring = new WCHAR[dwChars];
		wcsncpy(pwszSubstring,pWide,dwChars-1);
		pwszSubstring[dwChars-1] = NULL;

		WideCharToMultiByte(	CP_ACP, 
								0, 
								pwszSubstring, 
								-1, 
								pLocal, 
								dwChars, 
								NULL, 
								NULL);

	delete [] pwszSubstring;
}
#endif

	return lstrlen(pLocal);
}

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

	BrowseCallback()

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

int CALLBACK BrowseCallback(HWND hWnd, 
							UINT uMsg, 
							LPARAM lParam, 
							LPARAM lpData)
{
	switch(uMsg)
	{
	case DSBM_QUERYINSERT:
		{
			BOOL fReturn = FALSE;
			DSBITEM *pItem = (DSBITEM*)lParam;

			/*
			If this is to the root item, get the distinguished name for the 
			object and set the display name to the distinguished name.
			*/
			if(!(pItem->dwState & DSBS_ROOT))
			{
				HRESULT hr;
				IADs	*pads;

				hr = ADsGetObject(pItem->pszADsPath , 
					IID_IADs, (LPVOID*)&pads);
				if(SUCCEEDED(hr))
				{
					VARIANT var;

					VariantInit(&var);
					hr = pads->Get(CComBSTR("distinguishedName"), &var);
					if(SUCCEEDED(hr))
					{
						if(VT_BSTR == var.vt)
						{
							WideCharToLocal(pItem->szDisplayName, 
								var.bstrVal, DSB_MAX_DISPLAYNAME_CHARS);
							pItem->dwMask |= DSBF_DISPLAYNAME;
							fReturn = TRUE;
					}
					
						VariantClear(&var);
				}
				
					pads->Release();
			}
			
		}

			return fReturn;
	}
		break;
}

	return FALSE;
}

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

	BrowseForContainer()

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

HRESULT BrowseForContainer(HWND hwndParent, LPOLESTR *ppContainerADsPath)
{
	HRESULT hr = E_FAIL;
	DSBROWSEINFO dsbi;
	OLECHAR wszPath[MAX_PATH * 2];
	DWORD result;
 
	if(!ppContainerADsPath)
	{
		return E_INVALIDARG;
}
 
	ZeroMemory(&dsbi, sizeof(dsbi));
	dsbi.hwndOwner = hwndParent;
	dsbi.cbStruct = sizeof (DSBROWSEINFO);
	dsbi.pszCaption = TEXT("Browse for an Active Directory Container");
	dsbi.pszTitle = TEXT("Select an Active Directory container.");
	dsbi.pszRoot = NULL;
	dsbi.pszPath = wszPath;
	dsbi.cchPath = sizeof(wszPath)/sizeof(OLECHAR);
	dsbi.dwFlags = DSBI_INCLUDEHIDDEN |
					DSBI_IGNORETREATASLEAF|
					DSBI_RETURN_FORMAT;
	dsbi.pfnCallback = BrowseCallback;
	dsbi.lParam = 0;
	dsbi.dwReturnFormat = ADS_FORMAT_X500;
 
	// Display the browse dialog box.
	result = DsBrowseForContainer(&dsbi); // Returns -1, 0, IDOK, or IDCANCEL.
	if(IDOK == result)
	{
		// Allocate memory for the string.
		*ppContainerADsPath = (OLECHAR *)CoTaskMemAlloc (sizeof(OLECHAR)*(wcslen(wszPath)+1));
		if(*ppContainerADsPath)
		{
			wcscpy(*ppContainerADsPath, wszPath);
			// Caller must free using CoTaskMemFree. 
			hr = S_OK;
	}
		else
		{
			hr = E_FAIL;
	}
}
	else
	{
		hr = E_FAIL;
}
 
	return hr;
}