容器浏览器

应用程序可使用 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_BANNERDSBROWSEINFO 结构的 pszTitle 成员显示的静态文本控件的标识符。 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;
}