需求:在標準「開啟檔案」對話框右側加入圖片預覽區。本文採用 CFileDialog 派生 + Hook 截獲 CDN_SELCHANGE + 子對話框模板 方案,並解決 Win98/Win2000/XP 風格差異、多選緩衝區、預覽區佈局等實戰問題。
class CFileDialogEx : public CFileDialog
{
// Hook 回調靜態函數
static UINT_PTR CALLBACK OFNHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 內部預覽處理
void OnSelChange(HWND hDlg);
// ... 其他成員
};
建構函數中設定 m_ofn:
m_ofn.Flags |= OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLETEMPLATE;
m_ofn.lpfnHook = OFNHookProc;
m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG_HOOK); // 預覽區模板
m_ofn.hInstance = AfxGetInstanceHandle();
Static Text (ID: IDC_PIC),屬性:Notify, Sunken,作為圖片顯示區。UINT_PTR CALLBACK CFileDialogEx::OFNHookProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NOTIFY)
{
OFNOTIFY* pNotify = (OFNOTIFY*)lParam;
if (pNotify->hdr.code == CDN_SELCHANGE)
{
CFileDialogEx* pThis = (CFileDialogEx*)pNotify->hdr.lParam; // lParamCustData 傳 this
pThis->OnSelChange(hDlg);
}
}
return 0;
}
void CFileDialogEx::OnSelChange(HWND hDlg)
{
// 取得選中檔案完整路徑
TCHAR szPath[MAX_PATH];
CommDlg_OpenSave_GetFilePath(GetParent(hDlg), szPath, MAX_PATH);
// 載入圖片至 IDC_PIC (需自行實作 CPicture 載入 BMP/JPG/GIF 並 StretchBlt 繪製)
// ...
}
// 檢測 OS 版本決定結構體大小,控制對話框外觀
DWORD dwVer = GetVersion();
if (dwVer < 0x80000000) // NT 核心 (Win2000/XP/...)
m_ofn.lStructSize = 88; // OPENFILENAME_SIZE_VERSION_400 (含 Places Bar)
else
m_ofn.lStructSize = 76; // Win98 經典尺寸
此技巧讓同一套代碼在 Win98 顯示舊風格,在 2K/XP 顯示帶左側快捷列的新風格。
// 靜態大緩衝
TCHAR szBuf[4096] = {0};
dlg.m_ofn.lpstrFile = szBuf;
dlg.m_ofn.nMaxFile = 4096;
dlg.m_ofn.Flags |= OFN_ALLOWMULTISELECT;
或動態分配 (配合 CommDlg_OpenSave_GetSpec/GetFolderPath 取得實際所需大小)。
MSDN 規定:模板中 ID 為 stc32 的 Static 控制項位置決定預覽區放置邊界。
stc32 放在模板右側,寬度即預覽區寬度。stc32 放在核取方塊上方,高度 = 預覽區高度 + 核取方塊高度。實測需反覆微調 stc32 位置才能達到預期佈局。
CFileDialogEx dlg(TRUE);
dlg.m_ofn.lpstrFilter = _T("圖片\0*.bmp;*.jpg;*.png\0所有\0*.*\0");
if (dlg.DoModal() == IDOK)
{
POSITION pos = dlg.GetStartPosition();
while (pos) { CString path = dlg.GetNextPathName(pos); /*處理*/ }
}
完整專案含 CPicture 多格式載入類、Hook 類、資源模板,可直接整合。