SHBrowseForFolderA 函式 (shlobj_core.h)

顯示可讓用戶選取 Shell 資料夾的對話框。

語法

PIDLIST_ABSOLUTE SHBrowseForFolderA(
  [in] LPBROWSEINFOA lpbi
);

參數

[in] lpbi

類型: LPBROWSEINFO

BROWSEINFO 結構的指標,其中包含用來顯示對話框的資訊。

傳回值

類型: PIDLIST_ABSOLUTE

會傳回 PIDL,指定相對於命名空間根目錄的選取資料夾位置。 如果使用者在對話框中選擇 [ 取消] 按鈕,則傳回值為 NULL

傳回的 PIDL 可能是資料夾快捷方式而非資料夾。 如需此案例的完整討論,請參閱一節。

備註

針對 Windows Vista 或更新版本,建議您搭配使用 IFileDialog 搭配 FOS_PICKFOLDERS 選項,而不是 SHBrowseForFolder 函式。 這會在挑選資料夾模式中使用 [開啟檔案] 對話框,而且是慣用的實作。

呼叫 SHBrowseForFolder之前,您必須先初始化元件物件模型 (COM) 。 如果您使用 CoInitializeEx 初始化 COM,則必須在其 dwCoInit 參數中設定COINIT_APARTMENTTHREADED旗標。 您也可以使用 CoInitializeOleInitialize,一律使用 Apartment 線程。 如果您需要拖放功能,建議使用 OleInitialize ,因為它會初始化必要的 OLE 和 COM。

注意如果 COM 是使用 CoInitializeEx 搭配 COINIT_MULTITHREADED 旗標來初始化,如果呼叫的應用程式使用 BROWSEINFO 結構中的BIF_USENEWUI或BIF_NEWDIALOGSTYLE旗標,SHBrowseForFolder 就會失敗。
 
呼叫應用程式負責呼叫 CoTaskMemFree ,以在不再需要時釋出 SHBrowseForFolder 所傳回的 IDList。

有兩種可用的對話框樣式。 默認會顯示較舊的樣式,而且無法重設大小。 較新的樣式提供一些額外的功能,包括對話框內的拖放功能、重新排序、刪除、快捷功能表、建立新資料夾的能力,以及其他快捷方式功能表命令。 一開始,它大於較舊的對話框,但使用者可以調整其大小。 若要使用較新的樣式指定對話框,請在 BROWSEINFO 結構的 ulFlags 成員中設定BIF_USENEWUI旗標。

如果您實作在 BROWSEINFO 結構的 lpfn 成員中指定的回呼函式,您會收到對話框的句柄。 此視窗句柄的其中一個用法是修改對話框的配置或內容。 因為無法重設大小,所以修改較舊的樣式對話框相當簡單。 修改較新的樣式對話框會比較困難,不建議這麼做。 它不僅具有與舊樣式不同的大小和版面配置,也會在每次使用者重設大小時變更其控件的維度和位置。

如果BIF_RETURNONLYFSDIRS旗標是在 BROWSEINFO 結構的 ulFlags 成員中設定,則 [確定] 按鈕仍會針對 “\server” 專案啟用,以及 “\server\share” 和目錄專案。 不過,如果用戶選取 「\server」 專案,將 SHBrowseForFolder 傳回的 PIDL 傳遞至 SHGetPathFromIDList 失敗。

自訂篩選

從 Windows XP 起, SHBrowseForFolder 支援對話框內容的自定義篩選。 若要建立自定義篩選,請遵循下列步驟。
  1. lpbi 參數所指向之 BROWSEINFO 結構的 ulFlags 成員中設定BIF_NEWDIALOGSTYLE旗標。
  2. 在相同 BROWSEINFO 結構的 lpfn 成員中指定回呼函式。
  3. 撰寫回呼函式的程式碼,以接收BFFM_INITIALIZED和BFFM_IUNKNOWN訊息。 在收到BFFM_IUNKNOWN訊息時,回呼函式的 lParam 參數包含對話框的 IUnknown 實作指標。 在該 IUnknown 上呼叫 QueryInterface,以取得 IFolderFilterSite 實例的指標。
  4. 建立實作 IFolderFilter 的物件。
  5. 呼叫 IFolderFilterSite::SetFilter,並傳遞至 IFolderFilter 的指標。 接著可以使用 IFolderFilter 方法來包含和排除樹狀結構中的專案。
  6. 建立篩選之後,就不再需要 IFolderFilterSite 介面。 如果您尚未進一步使用它,請呼叫 IFolderFilterSite::Release

處理快捷方式

注意 本節僅適用於 Windows 2000 和舊版系統。 根據預設,Windows XP 和更新版本系統會傳回快捷方式目標的 PIDL,而不是快捷方式本身,只要 未在 BROWSEINFO 結構中設定BIF_NOTRANSLATETARGETS旗標即可。
 
如果 SHBrowseForFolder 將 PIDL 傳回至快捷方式,將 PIDL 傳送至 SHGetPathFromIDList 會傳回快捷方式本身的路徑,而不是其目標的路徑。 您可以使用 IShellLink 介面來取得快捷方式目標的路徑,如本範例所示。
#include 

// Macros for interface casts
#ifdef __cplusplus
#define IID_PPV_ARG(IType, ppType) IID_##IType, reinterpret_cast(static_cast(ppType))
#else
#define IID_PPV_ARG(IType, ppType) &IID_##IType, (void**)(ppType)
#endif

// Retrieves the UIObject interface for the specified full PIDL
STDAPI SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
{
    LPCITEMIDLIST pidlChild;
    IShellFolder* psf;

    *ppv = NULL;

    HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
    if (SUCCEEDED(hr))
    {
        hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);
        psf->Release();
    }
    return hr;
}
 
#define ILSkip(pidl, cb)       ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
#define ILNext(pidl)           ILSkip(pidl, (pidl)->mkid.cb)
 
HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
{
    DWORD cbTotal = 0;

    if (pidl)
    {
        LPCITEMIDLIST pidl_temp = pidl;
        cbTotal += sizeof (pidl_temp->mkid.cb);

        while (pidl_temp->mkid.cb) 
        {
            cbTotal += pidl_temp->mkid.cb;
            pidl_temp += ILNext (pidl_temp);
        }
    }
    
    *ppidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);
    
    if (*ppidl)
        CopyMemory(*ppidl, pidl, cbTotal);
 
    return  *ppidl ? S_OK: E_OUTOFMEMORY;
}
 
// Get the target PIDL for a folder PIDL. This also deals with cases of a folder  
// shortcut or an alias to a real folder.
STDAPI SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
{
    IShellLink *psl;
	
    *ppidl = NULL;
    
    HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_PPV_ARG(IShellLink, &psl));
    
    if (SUCCEEDED(hr))
    {
        hr = psl->GetIDList(ppidl);
        psl->Release();
    }
    
    // It's not a folder shortcut so get the PIDL normally.
    if (FAILED(hr))
        hr = SHILClone(pidlFolder, ppidl);
    
    return hr;
}

// Get the target folder for a folder PIDL. This deals with cases where a folder
// is an alias to a real folder, folder shortcuts, the My Documents folder, and 
// other items of that nature.
STDAPI SHGetTargetFolderPath(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
{
    LPITEMIDLIST pidlTarget;
	
    *pszPath = 0;

    HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);
    
    if (SUCCEEDED(hr))
    {
        SHGetPathFromIDListW(pidlTarget, pszPath);   // Make sure it is a path
        CoTaskMemFree(pidlTarget);
    }
    
    return *pszPath ? S_OK : E_FAIL;
}

// Retrieves the UIObject interface for the specified full PIDLstatic 
HRESULT SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
{    
    LPCITEMIDLIST pidlChild;    
    IShellFolder* psf;    
    *ppv = NULL;    
    
    HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&psf, &pidlChild);    
    if (SUCCEEDED(hr))    
    {        
        hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);        
        psf->Release();    
    }    
    return hr;
}

static HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
{    
    DWORD cbTotal = 0;    
    if (pidl)
    {        
        LPCITEMIDLIST pidl_temp = pidl;        
        cbTotal += pidl_temp->mkid.cb;        
        
        while (pidl_temp->mkid.cb)         
        {            
            cbTotal += pidl_temp->mkid.cb;            
            pidl_temp = ILNext(pidl_temp);        
        }    
    }    
    
    *ppidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);    
    if (*ppidl)        
        CopyMemory(*ppidl, pidl, cbTotal);    
        
    return  *ppidl ? S_OK: E_OUTOFMEMORY;
}
    
// Get the target PIDL for a folder PIDL. This also deals with cases of a folder  
// shortcut or an alias to a real folder.
static HRESULT SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
{    
    IShellLink *psl;    
    *ppidl = NULL;    
    
    HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_IShellLink, (LPVOID*)&psl);    
    if (SUCCEEDED(hr))    
    {        
        hr = psl->GetIDList(ppidl);        
        psl->Release();    
    }    
    
    // It's not a folder shortcut so get the PIDL normally.    
    if (FAILED(hr))        
        hr = SHILClone(pidlFolder, ppidl);    
    return hr;
}

// Get the target folder for a folder PIDL. This deals with cases where a folder
// is an alias to a real folder, folder shortcuts, the My Documents folder, 
// and so on.
STDAPI SHGetTargetFolderPath(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
{    
    LPITEMIDLIST pidlTarget;    
    *pszPath = 0;    
    
    HRESULT hr = SHGetTargetFolderIDList(pidlFolder, &pidlTarget);    
    if (SUCCEEDED(hr))    
    {        
        SHGetPathFromIDListW(pidlTarget, pszPath);   
        
        // Make sure it is a path        
        CoTaskMemFree(pidlTarget);    
    }    
    
    return *pszPath ? S_OK : E_FAIL;
}

注意

shlobj_core.h 標頭會根據 UNICODE 預處理器常數的定義,將 SHBrowseForFolder 定義為別名,自動選取此函式的 ANSI 或 Unicode 版本。 混合使用編碼中性別名與非編碼中性的程序代碼,可能會導致編譯或運行時間錯誤不符。 如需詳細資訊,請參閱 函式原型的慣例

規格需求

需求
最低支援的用戶端 Windows XP [僅限傳統型應用程式]
最低支援的伺服器 Windows 2000 Server [僅限傳統型應用程式]
目標平台 Windows
標頭 shlobj_core.h (包含 Shlobj.h、Shlobj_core.h)
程式庫 Shell32.lib
Dll Shell32.dll (4.0 版或更新版本)

另請參閱

開啟並儲存為對話框