首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Win32 開發入門(20):瀏覽資料夾 - SHBrowseForFolder 與 PIDL 處理詳解

     編輯:關於C++

使用 Shell 函式 SHBrowseForFolder 顯示資料夾選擇對話框,需處理 COM 初始化、BROWSEINFO 設定、PIDL 回傳值轉換完整路徑。本文完整實作與關鍵結構解析。

核心步驟

  1. CoInitialize(NULL) 初始化 COM 單元
  2. 填寫 BROWSEINFO 結構
  3. 呼叫 SHBrowseForFolder 取得 PIDLIST_ABSOLUTE
  4. SHGetPathFromIDList 將 PIDL 轉為檔案系統路徑
  5. CoTaskMemFree 釋放 PIDL 記憶體
  6. CoUninitialize 清理 COM

BROWSEINFO 關鍵成員設定


BROWSEINFO bi = {0};
bi.hwndOwner = hWnd;                    // 擁有者視窗
bi.pidlRoot = NULL;                     // 從桌面開始
bi.pszDisplayName = displayName;        // 接收顯示名稱緩衝區 (MAX_PATH)
bi.lpszTitle = L"請選擇資料夾";         // 對話框標題
bi.ulFlags = BIF_RETURNONLYFSDIRS       // 僅回傳檔案系統目錄
           | BIF_DONTGOBELOWDOMAIN      // 不顯示網路鄰域以下
           | BIF_NEWDIALOGSTYLE;        // Vista+ 新樣式(可調整大小)
bi.lpfn = NULL;                         // 無回呼函式
bi.lParam = 0;

常用旗標 (ulFlags) 詳細

旗標效果
BIF_RETURNONLYFSDIRS僅允許選擇檔案系統目錄(排除虛擬資料夾)
BIF_DONTGOBELOWDOMAIN網路層級停在域/工作群組,不深入伺服器
BIF_NEWDIALOGSTYLE可調整大小、支援新 UI、預設展開
BIF_EDITBOX包含編輯框可手動輸入路徑 (舊版)
BIF_VALIDATE配合回呼驗證輸入路徑有效性
BIF_BROWSEINCLUDEFILES允許選擇檔案(非僅資料夾)
BIF_SHAREABLE包含共享資源

完整實作程式碼


case IDM_BROWSE_FOLDER: {
    BROWSEINFO bi = {0};
    wchar_t displayName[MAX_PATH] = {0};
    wchar_t fullPath[MAX_PATH] = {0};

    bi.hwndOwner = hWnd;
    bi.pidlRoot = NULL;
    bi.pszDisplayName = displayName;
    bi.lpszTitle = L"請選擇資料夾";
    bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_NEWDIALOGSTYLE;

    CoInitialize(NULL);
    PIDLIST_ABSOLUTE pidl = SHBrowseForFolder(&bi);

    if (pidl) {
        // PIDL 轉完整路徑
        if (SHGetPathFromIDList(pidl, fullPath)) {
            HWND hDisplay = GetDlgItem(hDlg, IDC_DISPLAY);
            SetWindowText(hDisplay, fullPath);
        }
        // 釋放 PIDL (COM 記憶體分配器)
        CoTaskMemFree(pidl);
    }
    CoUninitialize();
    break;
}

PIDL (Item ID List) 核心觀念

  • Shell 命名空間中的物件識別碼(類似檔案系統 inode)
  • 不透明二進位結構,**不可直接解析**,需用 Shell API 操作
  • 記憶體由 IMalloc (Shell 分配器) 管理,**必須用 CoTaskMemFree 釋放**
  • SHGetPathFromIDList 僅對檔案系統物件有效,虛擬資料夾返回 FALSE

執行結果

現代替代方案

  • IFileDialog (Vista+):FOS_PICKFOLDERS 模式,COM 介面、支援自訂、非同步。
    
    IFileDialog* pfd;
    CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
                     IID_PPV_ARGS(&pfd));
    pfd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM);
    pfd->Show(hWnd);
    IShellItem* psi; pfd->GetResult(&psi);
    PWSTR path; psi->GetDisplayName(SIGDN_FILESYSPATH, &path);
    // 使用 path... CoTaskMemFree(path);
    
  • .NET:FolderBrowserDialog / OpenFileDialog (設定 ValidateNames=false + CheckFileExists=false + 自訂)。

常見錯誤

  1. 忘記 CoInitialize/CoUninitialize 配對 → COM 錯誤、記憶體洩漏。
  2. 使用 free() 或 delete 釋放 PIDL → 堆積損毀,必須 CoTaskMemFree。
  3. pszDisplayName 緩衝區過小 → 截斷,建議 MAX_PATH (260) 或更大。
  4. 未檢查 SHGetPathFromIDList 返回值直接使用路徑 → 虛擬資料夾導致空字串。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved