Directory Services

Directory Object Picker

The directory object picker dialog box enables a user to select one, or more, objects from the Active Directory global catalog, a Microsoft Windows 2000 domain or computer, a Microsoft Windows NT 4.0 domain or computer, or a workgroup. The object types from which a user can select include user, contact, group, and computer objects. For more information about Active Directory, see the Active Directory.

To display an object picker dialog box:

  1. Call the CoCreateInstance or CoCreateInstanceEx function to create an instance of the IDsObjectPicker interface.
  2. Call the IDsObjectPicker::Initialize method to initialize the dialog box.
  3. Call the IDsObjectPicker::InvokeDialog method to display the dialog box.
  4. Call the IDataObject::GetData method of the IDataObject instance returned by the object picker dialog box to retrieve the CFSTR_DSOP_DS_SELECTION_LIST data. The CFSTR_DSOP_DS_SELECTION_LIST clipboard format provides an HGLOBAL that contains a DS_SELECTION_LIST structure. The DS_SELECTION_LIST structure contains data about the items selected in the object picker dialog box.

If the Security Identifier (SID) is required for an object, this should be requested directly from the object picker by adding the objectSID attribute to the list of attributes to retrieve for the selected object. Passing the returned object name to the LsaLookupNames or LookupAccountName function is not recommended because the name lookup will be redundant and may fail in some cases.

If a reference to any selected objects will be saved, the distinguished name should not be saved because the object may move, get renamed, or may change due to locale differences. For security principals, the objectSID should be requested for the object and securely saved. If the name of the security principal is needed later, it can be retrieved with the LookupAccountSid function. For all other objects, the objectGUID should be requested and saved.

Initialization

When the object picker dialog box is initialized, a set of scope types and filters is specified. The specified scope types determine the locations, domains or computers for example, from which a user can select objects. The filters determine the types of objects that a user can select from a given scope type. For more information, see the Scopes and Filters section below.

By default, a user can select a single object in the directory object picker dialog box. To enable multiple selections, set the DSOP_FLAG_MULTISELECT flag in the flOptions member of the DSOP_INIT_INFO structure when the dialog box initialized.

Scopes and Filters

The Look in drop-down list contains the scopes from which a user can select objects. A scope is a domain, computer, workgroup, or global catalog that stores data about, and provides access to, a set of available objects. The entries in the scope list depend on the scope types and the target computer specified when the IDsObjectPicker::Initialize method was last called to initialize the object picker dialog box.

A scope type is a generic category of scopes, such as all domains in the enterprise to which the target computer belongs, or the global catalog for the target computer's enterprise, or the target computer itself. For each specified scope type, the dialog box uses the context of the target computer to determine the scope list entries.

The IDsObjectPicker::Initialize method takes a pointer to a DSOP_INIT_INFO structure that contains an array of DSOP_SCOPE_INIT_INFO structures. Each entry in the DSOP_SCOPE_INIT_INFO array specifies one or more scope types as well as applicable filters and other attributes. The filters determine the types of objects, such as users, groups, contacts, and computers, that the user can select from a given scope type. When the user selects a scope from the list, the dialog box applies the filters for that scope type to display a list of objects from which the user can select.

Each DSOP_SCOPE_INIT_INFO structure contains a DSOP_FILTER_FLAGS structure that specifies the filters for that scope type. The DSOP_FILTER_FLAGS structure distinguishes between up-level and down-level scopes:

There are two sets of filter flags defined for use in the DSOP_FILTER_FLAGS structure: one for up-level scopes and one for down-level scopes. The Uplevel member of the DSOP_FILTER_FLAGS structure is a DSOP_UPLEVEL_FILTER_FLAGS structure that specifies the filters for up-level scopes. The flDownlevel member of the DSOP_FILTER_FLAGS structure is a set of flags that specify the filters for down-level scopes.

Example

The following code example shows how to initialize, display, and process the results of an object picker dialog box.

#include <objsel.h>

HRESULT InitObjectPicker(IDsObjectPicker *pDsObjectPicker);
HRESULT ProcessSelectedObjects(IDataObject *pdo);

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

	main()

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

void main(void) 
{
	HRESULT hr = S_OK;
	IDsObjectPicker *pDsObjectPicker = NULL;
	IDataObject *pdo = NULL;

	hr = CoInitialize(NULL);
	if(FAILED(hr)) 
	{
		return;
}
 
	// Create an instance of the object picker. 
	hr = CoCreateInstance(  CLSID_DsObjectPicker,
							NULL,
							CLSCTX_INPROC_SERVER,
							IID_IDsObjectPicker,
							(void**) &pDsObjectPicker);
	if(SUCCEEDED(hr))
	{
		// Initialize the object picker instance. 
		hr = InitObjectPicker(pDsObjectPicker);
		if(SUCCEEDED(hr))
		{
			HWND hwndParent = GetConsoleWindow(); // Supply a window handle to the application.

			// Invoke the modal dialog box.
			hr = pDsObjectPicker->InvokeDialog(hwndParent, &pdo);
			if (hr == S_OK) 
			{
				ProcessSelectedObjects(pdo);
				pdo->Release();
		}
			else if (hr == S_FALSE)
			{
				printf("User canceled object picker dialog\n");
		}
	}
}

	pDsObjectPicker->Release();

	CoUninitialize();

	printf("\nPress <enter> to exit:");
	getchar();
}

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

	InitObjectPicker()

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

HRESULT InitObjectPicker(IDsObjectPicker *pDsObjectPicker) 
{
	if(NULL == pDsObjectPicker)
	{
		return E_INVALIDARG;
}

	DSOP_SCOPE_INIT_INFO aScopeInit[1];
	DSOP_INIT_INFO  InitInfo;
 
	// Initialize the DSOP_SCOPE_INIT_INFO array.
	ZeroMemory(aScopeInit, sizeof(aScopeInit));
 
	// Combine multiple scope types in a single array entry.
	aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
	aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
						 | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
 
	// Set up-level and down-level filters to include only computer objects.
	// Up-level filters apply to both mixed and native modes.
	// Be aware that the up-level and down-level flags are different.
 
	aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
	aScopeInit[0].FilterFlags.flDownlevel =  DSOP_DOWNLEVEL_FILTER_COMPUTERS;
 
	// Initialize the DSOP_INIT_INFO structure.
	ZeroMemory(&InitInfo, sizeof(InitInfo));
 
	InitInfo.cbSize = sizeof(InitInfo);
	InitInfo.pwzTargetComputer = NULL;  // Target is the local computer.
	InitInfo.cDsScopeInfos = sizeof(aScopeInit)/sizeof(DSOP_SCOPE_INIT_INFO);
	InitInfo.aDsScopeInfos = aScopeInit;
	InitInfo.flOptions = DSOP_FLAG_MULTISELECT;

	// Initialize can be called multiple times, but only the last call has effect.
	// Be aware that object picker makes its own copy of InitInfo.
	return pDsObjectPicker->Initialize(&InitInfo);
}

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

	ProcessSelectedObjects()

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

HRESULT ProcessSelectedObjects(IDataObject *pdo) 
{
	if(NULL == pdo)
	{
		return E_INVALIDARG;
}

	HRESULT	 hr;
	STGMEDIUM   stm;
	FORMATETC   fe;
 
	// Get the global memory block that contain the user's selections.
	fe.cfFormat = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
	fe.ptd = NULL;
	fe.dwAspect = DVASPECT_CONTENT;
	fe.lindex = -1;
	fe.tymed = TYMED_HGLOBAL;

	hr = pdo->GetData(&fe, &stm);
	if(SUCCEEDED(hr))
	{
		PDS_SELECTION_LIST pDsSelList = NULL;

		// Retrieve a pointer to DS_SELECTION_LIST structure.
		pDsSelList = (PDS_SELECTION_LIST)GlobalLock(stm.hGlobal);
		if(NULL != pDsSelList)
		{
			ULONG i;

			// Loop through DS_SELECTION array of selected objects.
			for (i = 0; i < pDsSelList->cItems; i++) 
			{
				printf("Object %u\n", i);
				printf("  Name '%ws'\n", 
						pDsSelList->aDsSelection[i].pwzName);
				printf("  Class '%ws'\n", 
						pDsSelList->aDsSelection[i].pwzClass);
				printf("  Path '%ws'\n", 
						pDsSelList->aDsSelection[i].pwzADsPath);
				printf("  UPN '%ws'\n", 
						pDsSelList->aDsSelection[i].pwzUPN);
		}

			GlobalUnlock(stm.hGlobal);
	}
		else
		{
			hr = E_POINTER;
	}

		ReleaseStgMedium(&stm);
}

	return hr;
}