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

Win32 開發入門(19):瀏覽開啟檔案 - GetOpenFileName 與 CLR OpenFileDialog 雙方案

     編輯:關於C++

檔案開啟/儲存對話框提供兩種實作:傳統 GetOpenFileName (C 風格) 與 CLR 整合 System.Windows.Forms.OpenFileDialog。本文完整對比兩種方案實作細節與避坑指南。

方案一:傳統 GetOpenFileName (純 Win32)

OPENFILENAME 關鍵成員


OPENFILENAME ofn = {0};
wchar_t filename[MAX_PATH] = {0};

ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hDlg;
ofn.lpstrFilter = L"所有檔案\0*.*\0文字檔\0*.txt\0MP3\0*.mp3\0";  // 雙\0結尾
ofn.nFilterIndex = 1;                          // 預設篩選器 (1-based)
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;  // 檢查存在性
ofn.lpstrTitle = L"選擇要開啟的檔案";

篩選器字串格式

  • 格式:描述1\0模式1\0描述2\0模式2\0\0
  • 每段以單一 \0 分隔,**結尾雙重 \0\0**
  • 字串常值自動附加單一 \0,故程式碼中寫一個 \0 即可形成雙重結尾

完整呼叫


if (GetOpenFileName(&ofn)) {
    HWND hEdit = GetDlgItem(hDlg, IDC_EDIT_FILE);
    SetWindowText(hEdit, filename);
}

方案二:CLR OpenFileDialog (C++/CLI 整合)

專案設定

  1. 專案屬性 → **Common Language Runtime 支援**:/clr
  2. 加入參考:System.Windows.Forms.dll
  3. 程式碼加入:using namespace System::Windows::Forms;

實作程式碼


if (LOWORD(wParam) == IDC_BTN_OPEN_CLR) {
    OpenFileDialog^ dlg = gcnew OpenFileDialog();
    dlg->Filter = L"所有檔案|*.*|圖片檔|*.jpg";  // '|' 分隔,.NET 風格
    dlg->FilterIndex = 1;
    dlg->CheckFileExists = true;

    if (dlg->ShowDialog() == DialogResult::OK) {
        // 轉換 System::String^ → const wchar_t*
        pin_ptr<const wchar_t> nativePath = PtrToStringChars(dlg->FileName);
        HWND hEdit = GetDlgItem(hDlg, IDC_EDIT_FILE);
        SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)nativePath);
    }
}

關鍵避坑:STA 執行緒模型

  • OpenFileDialog 需單一執行緒單元 (STA)
  • 專案屬性 → **Linker → Advanced → CLR Thread Model** → STA (/CLRTHREADATTRIBUTE:STA)
  • 否則 ShowDialog() 拋出 System.Threading.ThreadStateException

執行結果對比

兩方案詳細對比

維度GetOpenFileNameOpenFileDialog (CLR)
相依性純 Win32 (comdlg32.dll)需 /clr、.NET Framework
程式碼風格C 結構體、手動記憶體Managed 物件、GC 自動管理
篩選器語法\0 分隔、雙重結尾| 分隔、.NET 慣用
Unicode 支援原生 wchar_t原生 String^ (UTF-16)
自訂擴充Hook 程序 OFNHOOKPROC事件、繼承、自訂控制項
部署大小極小需 .NET Runtime
適用專案純原生、輕量、嵌入式混合模式、既有 .NET 專案

現代替代:IFileDialog (Vista+)


IFileDialog* pfd;
CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
                 IID_PPV_ARGS(&pfd));
pfd->SetFileTypes(3, (COMDLG_FILTERSPEC[]){
    {L"所有檔案", L"*.*"}, {L"文字檔", L"*.txt"}, {L"MP3", L*.mp3}
});
pfd->SetOptions(FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST);
if (SUCCEEDED(pfd->Show(hWnd))) {
    IShellItem* psi; pfd->GetResult(&psi);
    PWSTR path; psi->GetDisplayName(SIGDN_FILESYSPATH, &path);
    // 使用 path... CoTaskMemFree(path);
}
pfd->Release();

優點:原生 COM、無 .NET 相依、支援自訂位置、非同步、高 DPI 友善。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved