Браузер контейнеров

Приложение может использовать функцию DsBrowseForContainer для отображения диалогового окна, которое можно использовать для просмотра контейнеров в доменной службе Active Directory. Диалоговое окно отображает контейнеры в виде дерева и позволяет пользователю перемещаться по дереву с помощью клавиатуры и мыши. Когда пользователь выбирает элемент в диалоговом окне, предоставляется ADsPath контейнера, выбранного пользователем.

DsBrowseForContainer принимает указатель на структуру DSBROWSEINFO, содержащую данные о диалоговом окне и возвращающую ADsPath выбранного элемента.

Элемент pszRoot — это указатель на строку Юникода, содержащую корневой контейнер дерева. Если pszRootNULL, дерево будет содержать все дерево.

Элемент pszPath получает ADsPath выбранного объекта. При первом отображении диалогового окна можно указать определенный контейнер, который будет отображаться. Это достигается путем установки pszPath в ADsPath элемента, который будет выбран, и задав флаг DSBI_EXPANDONOPEN в dwFlags.

Содержимое и поведение диалогового окна также можно контролировать во время выполнения путем реализации функции BFFCallBack. Функция BFFCallBack реализуется приложением и вызывается при возникновении определенных событий. Приложение может использовать эти события для управления отображением элементов в диалоговом окне, а также фактического содержимого диалогового окна. Например, приложение может фильтровать элементы, отображаемые в диалоговом окне, путем реализации функции BFFCallBack, которая может обрабатывать уведомление DSBM_QUERYINSERT. Когда получено уведомление DSBM_QUERYINSERT, используйте элемент pszADsPath структуры DSBITEM, чтобы определить, какой элемент будет вставлен. Если приложение определяет, что элемент не должен отображаться, он может скрыть элемент, выполнив следующие действия.

  1. Добавьте флаг DSBF_STATE в элемент dwMask структуры DSBITEM.
  2. Добавьте флаг DSBS_HIDDEN в элемент dwStateMask структуры DSBITEM.
  3. Добавьте флаг DSBS_HIDDEN в элемент dwState структуры DSBITEM.
  4. Возвращает ненулевое значение из функции BFFCallBack.

Помимо скрытия определенных элементов, приложение может изменять текст и значок, отображаемый для элемента, обрабатывая уведомление DSBM_QUERYINSERT. Дополнительные сведения см. в DSBITEM.

Функция BFFCallBack может использовать уведомление BFFM_INITIALIZED для получения дескриптора диалогового окна. Приложение может использовать этот дескриптор для отправки сообщений, таких как BFFM_ENABLEOK, в диалоговое окно. Дополнительные сведения о сообщениях, которые можно отправить в диалоговое окно, см. в BFFCallBack.

Дескриптор диалогового окна также можно использовать для прямого доступа к элементам управления в диалоговом окне. DSBID_BANNER — это идентификатор статического текстового элемента управления, в котором отображается элемент pszTitle структуры DSBROWSE INFO. DSBID_CONTAINERLIST — это идентификатор элемента управления представления дерева, используемого для отображения содержимого дерева. При возможности следует избегать использования этих элементов, чтобы предотвратить будущие проблемы совместимости приложений.

В следующем примере кода C++ показано, как использовать функцию dsBrowseForContainer для создания диалогового окна браузера контейнеров и реализации функции BFFCallBack. BFFCallBack использует уведомление DSBM_QUERYINSERT для изменения отображаемого имени каждого элемента на различающееся имя элемента.

#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_s(pLocal, pWide, dwChars);
    }
    else
    {
        wcsncpy_s(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_s(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 a 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.
    // Returns -1, 0, IDOK, or IDCANCEL.
    result = DsBrowseForContainer(&dsbi); 
    if(IDOK == result)
    {
        // Allocate memory for the string.
        *ppContainerADsPath = (OLECHAR*)CoTaskMemAlloc(
            sizeof(OLECHAR)*(wcslen(wszPath) + 1));
        if(*ppContainerADsPath)
        {
            wcscpy_s(*ppContainerADsPath, wszPath);
            // Caller must free using CoTaskMemFree. 
            hr = S_OK;
        }
        else
        {
            hr = E_FAIL;
        }
    }
    else
    {
        hr = E_FAIL;
    }
 
    return hr;
}