Common Dialog Boxes

Active Directory provides common dialog boxes that you can use from within your application to present lists of directory objects and to select, or allow users to select, the directory objects your program will work with. These dialog boxes include the container browser dialog box, the domain browser dialog box, and the object picker dialog box. The common dialog boxes are similar in purpose to the common Open and Save As dialog boxes that Windows provides.

You could create your own dialog boxes to present directory information and gather object selections, but why reinvent the wheel? Plus, the dialog boxes that Active Directory provides will be updated in future versions of Windows to use the latest in user interface design. I'm going to describe the container browser dialog box first because the method used to invoke it is a little different from the one used with the domain browser and object picker dialog boxes.

Container Browser Dialog Box

The container browser dialog box presents a list of containers in a tree view. A user can expand or collapse the various nodes of the tree and select a container. This type of dialog box is used mostly when a user needs to choose a location to copy or move an object to or perform some other operation that involves a container (rather than an individual object). Figure 8-1 shows the container browser in action.

Figure 8-1 Active Directory container browser dialog box.

The container browser dialog box is presented to the user by calling the DsBrowseForContainer function and passing it a DSBROWSEINFO structure with the options you want. When the user makes a selection and closes the dialog box, this function returns the ADsPath of the selected object in the pszPath member of the DSBROWSEINFO structure. The declaration for DsBrowseForContainer and the DSBROWSEINFO structure are as follows:

 int DsBrowseForContainer(
    PDSBROWSEINFO pInfo
);
typedef struct DSBROWSEINFOW {
    DWORD       cbStruct;
    HWND        hwndOwner;
    LPCWSTR     pszCaption;
    LPCWSTR     pszTitle;
    LPCWSTR     pszRoot;
    LPWSTR      pszPath;
    ULONG       cchPath;
    DWORD       dwFlags;
    BFFCALLBACK pfnCallback;
    LPARAM      lParam;
    DWORD       dwReturnFormat;
    LPCWSTR     pUserName;
    LPCWSTR     pPassword;
    LPWSTR      pszObjectClass;
    ULONG       cchObjectClass;
} DSBROWSEINFOW, *PDSBROWSEINFOW;

While DSBROWSEINFO contains many members, the only ones that are required to be set are pszPath and ccPath. The rest can be initialized to 0 to accept the default behavior for the dialog box. For DsBrowseForContainer to return the ADsPath of the selected object, the calling application must allocate a character buffer to hold the ADsPath. The ADsPath is returned in Unicode even on ANSI systems, so the buffer must allocate space based on wide characters. The number of characters is returned in the cchPath member, which tells DsBrowseForContainer how much space is available. This value is expressed in characters, not bytes.

Many options are available to customize the behavior and appearance of the dialog box. They are set in the dwFlags member of DSBROWSEINFO and can be any combination of the flags listed in Table 8-1, all of which start with DSBI.

DsBrowseForContainer Option Description

DSBI_CHECKBOXES

Not currently implemented. If set, turns on the checkbox style for the tree view (TVS_CHECKBOXES).

DSBI_ENTIREDIRECTORY

When specified, includes all the trusted domains on the server specified in pszPath (or the domain that the user is logged on to).

DSBI_EXPANDONOPEN

Instructs the tree view to expand to the level specified in pszPath.

DSBI_HASCREDENTIALS

When set, DsBrowseForContainer will use the credentials specified in pUserName and pPassword . Otherwise, default credentials are ignored.

DSBI_IGNORETREATASLEAF

Shows all container objects. Otherwise, the treatAsLeaf attribute for the displaySpecifier class is used to determine whether an object is a container and should be shown.

DSBI_INCLUDEHIDDEN

Shows all objects, including those with the showInAdvancedViewOnly attribute set.

DSBI_NOBUTTONS

Does not display expand (+) and collapse (-) symbols next to items.

DSBI_NOLINES

Does not display lines between objects.

DSBI_NOLINESATROOT

Does not display lines between root objects.

DSBI_NOROOT

Does not display the root object.

DSBI_RETURN_FORMAT

When set, DsBrowseForContainer will return the ADsPath string in the format specified in the dwReturnFormat member. Can be any of the ADS_FORMAT constants. The default is to use ADS_FORMAT_X500.

DSBI_RETURNOBJECTCLASS

When set, DsBrowseForContainer will also return the class name of the selected object. The calling application must allocate buffer space and put the address of the buffer into the pszObjectClass member, along with the number of characters allocated into the cchObjectClass member.

DSBI_SIMPLEAUTHENTICATE

Indicates that secure authentication is not needed when calling ADsOpenObject.

Table 8-1 Possible flags for the dwFlags member of DSBROWSEINFO.

After creating and initializing the DSBROWSEINFO structure, you call DsBrowseForContainer with the structure address. The dialog box will then be displayed to the user. When the user closes the dialog box, the return code will be either IDOK for success or IDCANCEL if the user pressed the Escape key or clicked the Cancel button. All other errors return –1. Listing 8-1 shows code from the DsBrowseForContainer sample included on the companion CD, which shows how to use the DsBrowseForContainer function. When the container dialog box is closed, the results are displayed in a message box.

 //------------------------------------------------------------------------
// Filename:    DsBrowseForContainer.cpp
// Description: Example using Active Directory DsBrowseForContainer 
//              function
// Platform:    Win32 Application
//------------------------------------------------------------------------
#define UNICODE
#define _UNICODE
// C++ and Compiler Support
#include <crtdbg.h>           // C-runtime debugging support
#include <tchar.h>            // Generic text handling
#include <stdio.h>            // Standard C I/O routines
#include <comdef.h>           // COM definitions // Windows Platform Support
#include <objbase.h>          // COM base object support
#include <shlobj.h>           // Shell support (dsclient req'd)
#include <initguid.h>         // GUID support (dsadmin req'd)
// Active Directory Support
#include <activeds.h>         // ADSI object support
#include <dsclient.h>         // Active Directory UI object support
#include <dsadmin.h>          // Active Directory Admin object support
#include <objsel.h>           // DsObjectPicker support
// Set compiler options
#pragma warning( push, 4 ) // Warning level 4 for this code
#pragma comment( lib, "activeds.lib" ) // Link to ADSI library
#pragma comment( lib, "adsiid.lib"   ) // Link to ADSI interface GUIDs
#pragma comment( lib, "dsuiext.lib"  ) // Link to Active Directory UI
// Handy macro to return number of elements in array (good for strings)
#define ARRAYSIZE(a)    (sizeof(a)/sizeof(a[0]))
//------------------------------------------------------------------------
// Function: _tWinMain
//           Entry point for Win32 applications
// Inputs:   HINSTANCE hInstance  Handle to current instance
//           HINSTANCE hPrevInstance  Previous instance (always NULL)
//           LPSTR lpCmdLine  Pointer to command line string
//           int nCmdShow  Show state (SW_xxx)
// Returns:  int  Program exit code 0 = no errors
// Notes:    _tWinMain is the character-set independent version of
//           WinMain.  Resolves to either WinMain or wWinMain, depending 
//           on character set in use.
//           Parameter names not used are commented out to avoid
//           compiler warning C4100; "unreferenced formal parameter"
//------------------------------------------------------------------------
int WINAPI _tWinMain( HINSTANCE/*hInstance*/,
                      HINSTANCE/*hPrevInstance*/, 
                      LPSTR/*lpCmdLine*/, int/*nCmdShow*/)
{
    // Initialize COM
    HRESULT hResult;
    CoInitialize( NULL );
    //-------------------------------------------
    // Set options for the dialog
    //-------------------------------------------
    DSBROWSEINFO dsbInfo = { NULL };  // Set all members to default
    dsbInfo.cbStruct = sizeof( dsbInfo );  // Set size for version purpose
    dsbInfo.hwndOwner = NULL;  // Window handle     dsbInfo.pszCaption = _T("Container Browser");  // Text for title bar
    dsbInfo.pszTitle = _T("This example presents this dialog and 
        displays the ADsPath of the chosen container. Please pick from 
        the list below...");  // Additional text
    dsbInfo.pszRoot = NULL;  // Do not specify a root object
    dsbInfo.dwFlags =  // Option flags
        DSBI_ENTIREDIRECTORY |  // Include all trusted domains
        DSBI_EXPANDONOPEN |  // Expand tree to pszPath
        DSBI_IGNORETREATASLEAF |  // Show all objects, vs. just containers
        DSBI_RETURN_FORMAT |  // Format paths based on ADS_FORMAT_*
        DSBI_RETURNOBJECTCLASS;  // Fill in pszObject class
    // Function to call back
    dsbInfo.pfnCallback = *DsBrowseCallBack;
    // Format ADsPaths using X.500
    dsbInfo.dwReturnFormat = ADS_FORMAT_X500;
    dsbInfo.pUserName = NULL;  // Specify current user name
    dsbInfo.pPassword = NULL;  // Specify current user password
    //-------------------------------------------
    // Allocate buffers to hold return values
    //-------------------------------------------
    // Class and ADsPath are always UNICODE
    WCHAR pszObjectClass[MAX_PATH] = { NULL };
    // Buffer to hold class name
    dsbInfo.pszObjectClass = pszObjectClass;
    // Size of classname buffer
    dsbInfo.cchObjectClass = ARRAYSIZE(pszObjectClass);
    // ADsPath to hold results
    WCHAR pszResult[MAX_PATH] = { NULL };
    // Place result in here
    dsbInfo.pszPath = pszResult;
    // Size of path string
    dsbInfo.cchPath = ARRAYSIZE(pszResult);
    // Display browser dialog
    hResult = DsBrowseForContainer( &dsbInfo );
    if ( hResult == IDOK )
        {
        //-------------------------------------------
        // Display returned object ADsPath
        //-------------------------------------------
        // Format information string
        _TCHAR pszMessage[1024] = { NULL };         _stprintf( pszMessage,
            _T("ADsPath: \t%ls \nClass Name: \t%ls \n"),
            pszResult,
            pszObjectClass);
        MessageBox( NULL, 
            pszMessage, 
            _T("DsBrowseForContainer Results"), 
            MB_OK | MB_ICONINFORMATION );
        }
    // Uninitialize COM
    CoUninitialize ();
    // Exit with any lingering hResult
    return ( hResult );
}

Listing 8-1 Using the DsBrowseForContainer function.

Another powerful feature of the DsBrowseForContainer function is the ability to have messages sent to a function you specify. You specify the address of the callback function in the pfnCallback member of the DSBROWSEINFO structure. The callback function receives a message in the msg parameter along with data in the lParam and lpData parameters. The msg parameter will be one of the DSBM messages listed in Table 8-2.

Callback Function Message Description

DSBM_CHANGEIMAGESTATE

This message is documented as being sent when the image state in the tree view is changed. However, this message is currently not used.

DSBM_CONTEXTMENU

Sent whenever a user requests a context menu by right-clicking the mouse or, if using the keyboard, by pressing Shift+F10 or the Application key. However, a context menu is not displayed by default. You can then use the Windows TrackPopupMenu API to display a context menu at the location of the selected item.

DSBM_HELP

Sent whenever a user presses F1 or uses the Help button on the dialog box's title bar. The application can choose to display a ToolTip with additional information about the item selected.

DSBM_QUERYINSERT

Sent whenever the tree view is building a list of items. You can modify the item being added or filter it entirely.

Table 8-2 Messages for the DsBrowseForContainer callback function.

Listing 8-2 shows a framework of the callback function, displaying message information in the debug window. The complete source code is available on the companion CD.

Here's some information on an undocumented feature. In addition to the DSBM messages, the callback function is also called whenever the user changes his or her selection. The msg parameter is set to 0x02 and lpData points to an ADsPath of the item being selected, followed by the class name. In Listing 8-2, whenever the selection changes, the code sets the text above the tree control to show the ADsPath of the selected object. The dialog box's title bar is also set to the class name. Interestingly enough, the ADsPath string is always returned using the ADS_FORMAT_WINDOWS_NO_SERVER style, regardless of the DSBROWSE-INFO dwReturnFormat setting. As always, be extremely careful using undocumented features, as they are generally undocumented for a good reason, including being unsupported or being subject to change in the future. As a former Microsoft developer, I can be trusted on this.

 // Disable "conditional expression is constant"
// generated by _RPTx macros
#pragma warning( disable : 4127 )
//------------------------------------------------------------------------
// Function:  DsBrowseCallBack
//            Callback to filter and modify directory browser
// Inputs:    HWND hwnd  Window handle of dialog
//            UINT msg  Message number (DSBM_*)
//            LPARAM lpData  Pointer to data, depends on message type
//            LPARAM lParam  Instance data specified by caller
// Notes:     Parameter names not used are commented out to avoid
//            compiler warning C4100; "unreferenced formal parameter"
//------------------------------------------------------------------------
int CALLBACK DsBrowseCallBack( HWND/*hwnd*/, UINT msg, LPARAM lpData, 
    LPARAM/*lParam*/)
{
    PDSBITEM   pdsbItem = NULL;  // For DSBM_QUERYINSERT
    LPHELPINFO phlpInfo = NULL;  // For DSBM_HELP
    HWND       hWnd = NULL;      // For DSBM_CONTEXTMENU
    BOOL       bResult = FALSE;  // Default result is to ignore message     switch ( msg )
        {
        case DSBM_CONTEXTMENU:
            // User requested a context menu
            // lpData contains the HWND of the window,
            // the dialog box to the callback function
            // lpData contains the HWND of the item
            // Display information
            hWnd = (HWND)lpData;
            // Create popup menu
            _RPT1( _CRT_WARN, "DSBM_CONTEXTMENU: %x \n", hWnd );
            bResult = FALSE;
            break;
        case DSBM_HELP:
            // Used to forward the WM_HELP message from the 
            // dialog box to the callback function
            // lpData points to a HELPINFO structure
            // Display the X/Y location of mouse when help is selected
            // Can use this information to query the tree view control
            phlpInfo = (LPHELPINFO)lpData;
            _RPT2( _CRT_WARN, "DSBM_HELP: %u/%u\n",
                phlpInfo->MousePos.x, 
                phlpInfo->MousePos.y );
            break;
        case DSBM_QUERYINSERT:
            // Called before each item is inserted into 
            // the display. Can modify the name, icon, and state.
            // lpData points to DBSITEM structure
            _ASSERT(lpData);
            // Display item name
            pdsbItem = (PDSBITEM)lpData;
            _RPT2( _CRT_WARN, "DSBM_QUERYINSERT %d: %ls\n", msg, 
                pdsbItem->szDisplayName );
            // Return indicates item was not modified
            bResult = FALSE;
            break;
        case DSBM_QUERYINSERTA:
            // Called in addition to DSBM_QUERYINSERTW with 
            // ANSI version of DSBITEM
            bResult = FALSE;
            break;
        case 0x02:
            // UNDOCUMENTED
            // Called whenever selection changes
            // lpData contains pointer to selected item as a 
            // UNICODE ADsPath using ADS_FORMAT_WINDOWS_NO_SERVER
            // After the ADsPath string NULL character, 
            // the class name of the object always follows
            if (lpData)
                {
                WCHAR* pszADsPath = (WCHAR*)lpData;
                WCHAR* pszClassName = pszADsPath + 
                    _tcslen(pszADsPath) + 1;
                _RPT3( _CRT_WARN, "DSBM_??? %d: %ls %ls\n", msg, 
                    pszADsPath, pszClassName );
                // Copy the ADsPath to the banner text using the 
                // DSBID_BANNER control ID
                SendDlgItemMessage( 
                    hwnd,  // Windows handle of dialog box
                    DSBID_BANNER,  // Specify banner label control
                    WM_SETTEXT,  // Send message to change text
                    0,  // Not used
                    (LPARAM)pszADsPath);  // Set banner to ADsPath
                // Set the dialog caption to the class name
                SetWindowText(hwnd, pszClassName);
                }
            bResult = TRUE; //DEBUG
            break;
        default:
            // Unknown message, display in debug
            _RPT1( _CRT_WARN, "DsBrowseCallBack: %d\n", msg );
            break;
        }
    // Return the result
    return ( bResult );
}
#pragma warning( default : 4127 )  // Restore default behavior

Listing 8-2 A framework of the callback function.

Listing 8-2 uses a couple of features from the Microsoft Visual C++ run-time library. The _RPTx macros are handy for displaying printf style messages in the debugging window or for forcing an assert dialog box. However, they generate C4127 warnings, so I use a #pragma statement to disable those messages while retaining the warning level specified in the project settings.

Domain Browser Dialog Box

The domain browser dialog box is similar to the container browser dialog box. I won't cover this dialog box in as much detail because you are unlikely to use it as often. Instead of using a function, as the container browser dialog box does, the domain browser uses the IDsBrowseDomainTree interface. The user is shown a dialog box with just the specified domains, including any trusted domains, as shown in Figure 8-2.

Figure 8-2 Active Directory domain browser dialog box.

Listing 8-3 shows how to invoke the domain browser dialog box using the BrowseTo method of the IDsBrowseDomainTree interface.

 int WINAPI _tWinMain( HINSTANCE/*hInstance*/,
    HINSTANCE/*hPrevInstance*/, 
    LPSTR/*lpCmdLine*/, int/*nCmdShow*/)
{
    // Initialize COM
    CoInitialize( NULL );     //-------------------------------------------
    // Create an instance of the domain browser
    //-------------------------------------------
    IDsBrowseDomainTree *pobjDSBDomain = NULL;
    HRESULT hResult = CoCreateInstance( CLSID_DsDomainTreeBrowser,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IDsBrowseDomainTree,
        (void **) &pobjDSBDomain);
    // Ensure object was created
    if ( SUCCEEDED( hResult ) )
        {
        //-------------------------------------------
        // Display domain browser dialog
        //-------------------------------------------
        LPWSTR pszDomainName;
        hResult = pobjDSBDomain->BrowseTo(
            NULL,  // Owner window 
            &pszDomainName,  // Pointer to hold returned domain name
            DBDTF_RETURNFQDN |  // Return fully qualified domain name
            DBDTF_RETURNMIXEDDOMAINS |  // Show downlevel trust domains
            DBDTF_RETURNEXTERNAL |  // Show external trust domains 
         // DBDTF_RETURNINBOUND |  // Show trusting domains instead of 
                                   // trusted domains
            DBDTF_RETURNINOUTBOUND );  // Show both trusted and 
                                       // trusting domains
        if ( pszDomainName != NULL )
            // Display users selection
            MessageBox(NULL, pszDomainName, 
                _T("User selected the following domain"), MB_OK | 
                MB_ICONINFORMATION);
        // Free memory allocated for target string
        if ( pszDomainName )
            CoTaskMemFree ( pszDomainName );
        }
    // No longer need the object, release the interface
    if ( pobjDSBDomain )
        pobjDSBDomain->Release ();
    // Uninitialize COM and exit
    CoUninitialize ();
    // Exit with any lingering hResult
    return (hResult);
}

Listing 8-3 DsBrowseDomain.cpp showing how to invoke the domain browser dialog box using the BrowseTo method of the IDsBrowseDomainTree interface.

Object Picker Dialog Box

It's impossible to work with Active Directory and not have used the object picker dialog box. The Windows 2000 administrative tools use the object picker extensively when modifying groups and security settings. Selecting user objects is the most common use of this component; however, it does much more than that. Figure 8-3 shows an example of the object picker dialog box.

Figure 8-3 Object picker dialog box.

The object picker dialog box is an extremely useful component for developers of Active Directory–enabled applications. Instead of having to create a custom user interface, developer's lives are made easier because all the work of displaying objects and gathering input is wrapped up in a single COM object named DsObjectPicker.

Think of DsObjectPicker as the Active Directory version of the common Open dialog box provided by the Windows shell and used in most Windows-based applications. Unlike the container and domain browser dialog boxes, the object picker does not display the directory hierarchy. The DsObjectPicker is optimized for directory objects and is simplified for that task.

IDsObjectPicker

The DsObjectPicker object exposes a simple COM interface, IDsObjectPicker, which has two methods. The first is the Initialize method, which you use to set options for the dialog box, including scopes and filters, which I'll define shortly. The second is InvokeDialog, which displays the dialog box and returns the user's selections via the IDataObject interface.

When using DsObjectPicker, you specify the location in the directory to display, which object classes to show, and whether the user is allowed to pick multiple objects. The location is defined with a scope. There are two kinds of scope: up-level for Windows 2000 domains, and down-level for mixed-mode domains with Windows NT 4.0 or earlier domain controllers. The mechanism used to specify which objects to display for a scope is called a filter. The dialog box options are set using a DSOP_INIT_INFO structure, each containing an array of DSOP_SCOPE_INIT_INFO structures for each scope to be used. Filters are set per-scope by using the DSOP_FILTER_FLAGS and DSOP_UPLEVEL_FILTER_FLAGS structures.

After a user has made his or her choice of objects and clicks the OK button, information about the objects selected is returned via the COM IDataObject interface. IDataObject is a generic interface used to pass a data object between processes. In this case, the data object is formatted as a DS_SELECTION_LIST structure. This structure contains an array of DS_SELECTION structures, which is listed below.

 typedef struct _DS_SELECTION {
    PWSTR   pwzName;
    PWSTR   pwzADsPath;
    PWSTR   pwzClass;
    PWSTR   pwzUPN;
    VARIANT *pvarFetchedAttributes;
    ULONG   flScopeType;
} DS_SELECTION, *PDS_SELECTION;

Object Picker Sample

Listing 8-4 shows how to use the object picker dialog box from C++. This application opens the object picker dialog box and allows the user to select one or more users, contacts, or computers. When the user clicks OK, the name, class, ADsPath, and user principal name (UPN) for each object is displayed in a message box. Figure 8-4 shows a sample of the output.

Figure 8-4 Information displayed for the object selected in the object picker.

The sample calls the Initialize method of the IDsObjectPicker interface with a pointer to a DSOP_INIT_INFO structure that defines the scope and filter for the object picker. Then the sample invokes the object picker dialog box using the InvokeDialog method of the IDsObjectPicker interface. Finally, the sample processes the returned IDataObject objects and displays a message box with information about each object.

 int WINAPI _tWinMain( HINSTANCE/*hInstance*/, 
    HINSTANCE/*hPrevInstance*/, 
    LPSTR/*lpCmdLine*/, int/*nCmdShow*/)
{
    // Initialize COM
    CoInitialize( NULL );

    //-------------------------------------------
    // Create an instance of the object picker. 
    //-------------------------------------------
    IDsObjectPicker *pobjDSOPicker = NULL;
    HRESULT hResult = CoCreateInstance( CLSID_DsObjectPicker,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IDsObjectPicker,
        (void **) &pobjDSOPicker);
    // Ensure object was created
    if ( SUCCEEDED( hResult ) )
        {
        //-------------------------------------------
        // Initialize DsObjectPicker parameters
        //-------------------------------------------
        // Initialize an array of scopes
        static const int SCOPE_INIT_COUNT = 1;
        DSOP_SCOPE_INIT_INFO rgScopeInit[ SCOPE_INIT_COUNT ];
        // Set structure members to zero to indicate default
        ZeroMemory( rgScopeInit, 
            sizeof( DSOP_SCOPE_INIT_INFO ) * SCOPE_INIT_COUNT);
        //-------------------------------------------
        // Set scope options
        //-------------------------------------------
        // Set scope size (used to check version)
        rgScopeInit[0].cbSize = sizeof( DSOP_SCOPE_INIT_INFO );         // Set scope type to entire forest (i.e. enterprise)
        rgScopeInit[0].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN;
        // Returned objects should have ADsPath with the LDAP provider
        rgScopeInit[0].flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP;
        //-------------------------------------------------------------
        // Set Filter options to show users, computers, and contacts
        //-------------------------------------------------------------
        // Uplevel scope supports Active Directory
        rgScopeInit[0].FilterFlags.Uplevel.flBothModes =
            // Native or mixed mode domains
            // Show groups
        //  DSOP_FILTER_BUILTIN_GROUPS |
            // Show computers
            DSOP_FILTER_COMPUTERS |
            // Show contacts
            DSOP_FILTER_CONTACTS |
            // Show local distribution groups
         // DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL |
            // Show local security groups
         // DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE |
            // Show global distribution groups
         // DSOP_FILTER_GLOBAL_GROUPS_DL |
            // Show global security groups
         // DSOP_FILTER_GLOBAL_GROUPS_SE |
            // Show showInAdvancedViewOnly objects
         // DSOP_FILTER_INCLUDE_ADVANCED_VIEW |
            // Show universal distribution groups
         // DSOP_FILTER_UNIVERSAL_GROUPS_DL |
            // Show universal security groups
         // DSOP_FILTER_UNIVERSAL_GROUPS_SE |
            // Show users
            DSOP_FILTER_USERS ;    // Show users
            // Include well-known security principals
         // DSOP_FILTER_WELL_KNOWN_PRINCIPALS
        // Downlevel scope supports Windows NT 4.0
        rgScopeInit[0].FilterFlags.flDownlevel =
            DSOP_DOWNLEVEL_FILTER_COMPUTERS |  // Show computers
            DSOP_DOWNLEVEL_FILTER_USERS;       // Show users
        //-------------------------------------------
        // Create Initialization Structure
        //-------------------------------------------
        // Initialize the DSOP_INIT_INFO structure.
        DSOP_INIT_INFO  dsopInitInfo;
        ZeroMemory( &dsopInitInfo, sizeof( dsopInitInfo ) );
        // Set size of structure (used to check version)
        dsopInitInfo.cbSize = sizeof( dsopInitInfo );
        // Use local computer to determine domain
        dsopInitInfo.pwzTargetComputer = NULL;
        // Set the number of scopes that are part of this structure
        dsopInitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
        // Add scope(s) to structure
        dsopInitInfo.aDsScopeInfos = rgScopeInit;
        // Allow the user to select multiple objects
        dsopInitInfo.flOptions = DSOP_FLAG_MULTISELECT;
        // DsObjectPicker can retrieve certain attributes of 
        // selected objects
        // Not shown in this example. Instead, use the returned 
        // ADsPath to bind and work with selected objects.
#if defined(USE_ATTR_NAMES)
        // For each object, retrieve the lDAPDisplayName attribute
        PCWSTR pcwszAttrNames[] = { L"lDAPDisplayName" };
        dsopInitInfo.cAttributesToFetch = 1;
        dsopInitInfo.apwzAttributeNames = &pcwszAttrNames[0];
#else
        // Specify no attributes be returned (ADsPath is always available)
        dsopInitInfo.cAttributesToFetch = 0;
        dsopInitInfo.apwzAttributeNames = NULL;
#endif
        //----------------------------------------------
        // Initialize DsObjectPicker
        //----------------------------------------------
        // Initialize the object picker with the DS_INIT_INFO structure
        hResult = pobjDSOPicker->Initialize ( &dsopInitInfo );
        if ( SUCCEEDED ( hResult ) )
            {
            //-------------------------------------------
            // Display object picker dialog
            //-------------------------------------------             // Register the results data object format
            CLIPFORMAT cfDsObjectPicker = (CLIPFORMAT) 
                RegisterClipboardFormat( CFSTR_DSOP_DS_SELECTION_LIST );
            // Display the picker dialog, and return a IDataObject interface
            IDataObject *pobjDataObject = NULL;
            hResult = pobjDSOPicker->InvokeDialog( NULL, &pobjDataObject );
            if ( SUCCEEDED ( hResult ) )
                {
                // If not S_OK, user pressed Cancel button
                if ( hResult == S_OK )
                    {
                    //-------------------------------------------
                    // Get the user's selections
                    //-------------------------------------------
                    // Important to fill in all members of STGMEDIUM and 
                    // FORMATETC structures before calling GetData method
                    STGMEDIUM stgmedium = {  // Storage medium information
                        TYMED_HGLOBAL,  // Use global memory to hold data
                        NULL,  // Global memory handle
                        NULL };  // Indicate receiver will release medium
                    FORMATETC formatetc = {  // Data format information
                        cfDsObjectPicker,  // Registered clipboard format 
                                           // value
                        NULL,  // Independence device for data
                        DVASPECT_CONTENT,  // We want the content itself 
                        -1,  // No boundary break
                        TYMED_HGLOBAL };  // Use global memory to hold data
                    // Get the global memory block containing a user's 
                    // selections
                    hResult = pobjDataObject->GetData( 
                        &formatetc, &stgmedium );
                    if ( SUCCEEDED( hResult ) )
                        {
                        //-------------------------------------------
                        // Process selections
                        //-------------------------------------------
                        // Get a pointer to the data contained in 
                        // DS_SELECTION_LIST structure
                        DS_SELECTION_LIST *pdsslSelectedObjects = NULL;
                        pdsslSelectedObjects = (DS_SELECTION_LIST*) 
                            GlobalLock( stgmedium.hGlobal );
                        // Verify valid data
                        if ( pdsslSelectedObjects )
                            {
                            // Loop through array of selected objects
                            ULONG ulIndex;
                            for ( ulIndex = 0;
                                ulIndex < pdsslSelectedObjects->cItems;
                                ulIndex++)
                                {
                                // Display information for each object 
                                // selected
                                _TCHAR pszMessage[1024] = { NULL };
                                _stprintf( pszMessage,
                                    _T("Object #%u of %u selected. 
                                    \n\nName:\t%ws \nClass:\t%ws 
                                    \nADsPath:\t%ws \nUPN:\t%ws \n"),
                                    ulIndex + 1,
                                    pdsslSelectedObjects->cItems,
                                    pdsslSelectedObjects->
                                    aDsSelection[ulIndex].pwzName,
                                    pdsslSelectedObjects->
                                    aDsSelection[ulIndex].pwzClass,
                                    pdsslSelectedObjects->
                                    aDsSelection[ulIndex].pwzADsPath,
                                    pdsslSelectedObjects->
                                    aDsSelection[ulIndex].pwzUPN);
                                MessageBox( NULL, 
                                    pszMessage, 
                                    _T("Object Picker Results"), 
                                    MB_OK | MB_ICONINFORMATION );
                                }
                            // Release the data
                            GlobalUnlock( stgmedium.hGlobal );
                            }
                        }
                    // Release the storage medium
                    ReleaseStgMedium( &stgmedium );
                    }                 else // Success, but not S_OK; user pressed Cancel button
                    {
                    MessageBox( NULL,
                        _T("User pressed Cancel button."), 
                        _T("Object Picker Results"),
                        MB_OK | MB_ICONINFORMATION );
                    }
                // No longer need the selections; release 
                // IDataObject interface
                if ( pobjDataObject )
                    pobjDataObject->Release ();
                }
            }
        }
    // No longer need the DsObjectPicker; release IDsObjectPicker interface
    if ( pobjDSOPicker )
        pobjDSOPicker->Release ();
    // Uninitialize COM and exit
    CoUninitialize ();
    // Exit with any lingering hResult
    return (hResult);
}

Listing 8-4 DsObjectPicker.cpp showing how to use the object picker dialog box.



MicrosoftR WindowsR 2000 Active DirectoryT Programming
MicrosoftR WindowsR 2000 Active DirectoryT Programming
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 108

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net