容器浏览器

应用程序可以使用 DsBrowseForContainer 函数显示可用于浏览 Active Directory 域服务中的容器的对话框。 该对话框以树格式显示容器,使用户能够使用键盘和鼠标浏览树。 当用户在对话框中选择某个项时,将提供用户选择的容器的 ADsPath。

DsBrowseForContainer 获取指向包含对话框数据的 DSBROWSEINFO 结构的指针,并返回所选项的 ADsPath。

pszRoot 成员是指向包含树根容器的 Unicode 字符串的指针。 如果 pszRootNULL,则树将包含整个树。

pszPath 成员接收所选对象的 ADsPath。 在首次显示对话框时,可以指定可见和选择的特定容器。 为此,将 pszPath 设置为要选择的项的 ADsPath,并在 dwFlags 中设置标志 DSBI_EXPANDONOPEN 标志来实现此 目的。

对话框的内容和行为也可以在运行时通过实现 BFFCallBack 函数来控制。 BFFCallBack 函数由应用程序实现,并在发生某些事件时调用。 应用程序可以使用这些事件来控制对话框中的项的显示方式以及对话框的实际内容。 例如,应用程序可以通过实现可以处理 DSBM_QUERYINSERT 通知的 BFFCallBack 函数来筛选对话框中显示的项目。 收到 DSBM_QUERYINSERT 通知时,请使用 DSBITEM 结构的 pszADsPath 成员来确定要插入的项。 如果应用程序确定不应显示该项,则可以通过执行以下步骤来隐藏该项。

  1. DSBF_STATE 标志添加到 DSBITEM 结构的 dwMask 成员。
  2. DSBS_HIDDEN 标志添加到 DSBITEM 结构的 dwStateMask 成员。
  3. DSBS_HIDDEN 标志添加到 DSBITEM 结构的 dwState 成员。
  4. BFFCallBack 函数中返回非零值。

除了隐藏某些项之外,应用程序还可以通过处理 DSBM_QUERYINSERT 通知来修改为项显示的文本和图标。 有关详细信息,请参阅 DSBITEM

BFFCallBack 函数可以使用 BFFM_INITIALIZED 通知获取对话框的句柄。 应用程序可以使用此句柄将消息(如 BFFM_ENABLEOK)发送到对话框。 有关可发送到对话框的消息的详细信息,请参阅 BFFCallBack

对话框句柄还可用于直接访问对话框中的控件。 DSBID_BANNER 是静态文本控件的标识符,pszTitleDSBROWSEINFO 结构的成员显示在其中。 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;
}