Compartilhar via


Navegador de contêiner

Um aplicativo pode usar a função DsBrowseForContainer para exibir uma caixa de diálogo que pode ser usada para navegar pelos contêineres em um Serviço de Domínio Active Directory. A caixa de diálogo exibe os contêineres em um formato de árvore e permite que o usuário navegue pela árvore usando o teclado e o mouse. Quando o usuário seleciona um item na caixa de diálogo, o ADsPath do contêiner selecionado pelo usuário é fornecido.

DsBrowseForContainer leva um ponteiro para uma estrutura DSBROWSEINFO que contém dados sobre a caixa de diálogo e retorna o ADsPath do item selecionado.

O membro pszRoot é um ponteiro para uma cadeia de caracteres Unicode que contém o contêiner raiz da árvore. Se pszRoot for NULL, a árvore conterá a árvore inteira.

O membro pszPath recebe o ADsPath do objeto selecionado. É possível especificar um contêiner específico a ser visível e selecionado quando a caixa de diálogo for exibida pela primeira vez. Isso é feito definindo pszPath como o ADsPath do item a ser selecionado e definindo o sinalizador DSBI_EXPANDONOPEN em dwFlags.

O conteúdo e o comportamento da caixa de diálogo também podem ser controlados em tempo de execução implementando uma função BFFCallBack. A função BFFCallBack é implementada pelo aplicativo e é chamada quando determinados eventos ocorrem. Um aplicativo pode usar esses eventos para controlar como os itens na caixa de diálogo são exibidos, bem como o conteúdo real da caixa de diálogo. Por exemplo, um aplicativo pode filtrar os itens exibidos na caixa de diálogo implementando uma função BFFCallBack que pode manipular a notificação DSBM_QUERYINSERT. Quando uma notificação de DSBM_QUERYINSERT é recebida, use o membro pszADsPath da estrutura DSBITEM para determinar qual item está prestes a ser inserido. Se o aplicativo determinar que o item não deve ser exibido, ele poderá ocultá-lo executando as etapas a seguir.

  1. Adicione o sinalizador DSBF_STATE ao membro dwMask da estrutura DSBITEM .
  2. Adicione o sinalizador DSBS_HIDDEN ao membro dwStateMask da estrutura DSBITEM .
  3. Adicione o sinalizador DSBS_HIDDEN ao membro dwState da estrutura DSBITEM .
  4. Retorne um valor diferente de zero da função BFFCallBack.

Além de ocultar determinados itens, um aplicativo pode modificar o texto e o ícone exibidos para o item manipulando a notificação DSBM_QUERYINSERT. Para obter mais informações, consulte DSBITEM.

A função BFFCallBack pode usar a notificação BFFM_INITIALIZED para obter o identificador da caixa de diálogo. O aplicativo pode usar esse identificador para enviar mensagens, como BFFM_ENABLEOK, para a caixa de diálogo. Para obter mais informações sobre as mensagens que podem ser enviadas para a caixa de diálogo, consulte BFFCallBack.

O identificador da caixa de diálogo também pode ser usado para obter acesso direto aos controles na caixa de diálogo. DSBID_BANNER é o identificador do controle de texto estático no qual o membro pszTitle da estrutura DSBROWSEINFO é exibido. DSBID_CONTAINERLIST é o identificador do controle de exibição de árvore usado para exibir o conteúdo da árvore. O uso desses itens deve ser evitado, se possível, para evitar problemas futuros de compatibilidade de aplicativos.

O exemplo de código C++ a seguir mostra como usar a função DsBrowseForContainer para criar a caixa de diálogo do navegador de contêiner e implementar uma função BFFCallBack. O BFFCallBack usa a notificação DSBM_QUERYINSERT para alterar o nome de exibição de cada item para o nome distinto do 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_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;
}