核心模式:主視窗持有對話框指標,Create() 建立無模式對話框,DestroyWindow() 關閉,PostNcDestroy 自刪。
CModel
class CModel : public CDialog {
CWnd* m_pParent; int m_nID;
public:
CModel(CWnd* pParent = NULL) : CDialog(IDD, pParent) {
m_pParent = pParent; m_nID = IDD;
}
BOOL Create() { return CDialog::Create(m_nID, m_pParent); }
virtual void PostNcDestroy() { delete this; CDialog::PostNcDestroy(); }
};
// 開啟
if (!m_pDlg) {
m_pDlg = new CModel(this);
m_pDlg->Create();
GetDlgItem(IDC_EXPORT)->EnableWindow(FALSE); // 禁用觸發按鈕
} else {
m_pDlg->SetActiveWindow();
}
// 關閉
if (m_pDlg) { m_pDlg->DestroyWindow(); m_pDlg = NULL; }
優點:主視窗保持可操作、進度對話框可拖動、支援取消按鈕 (對話框內設 OnCancel 呼叫 DestroyWindow)。
策略:批次檔 + CreateProcess + 計時器輪詢完成旗標。
void CMyCompress::CreateBat(CString BatPath, CString ArjPath, CString BatName,
CString ArjFile, CString TempPath, CString ExitFlag, BOOL bCompress) {
CStdioFile f; f.Open(BatPath + BatName, CFile::modeCreate|CFile::modeWrite);
CString cmd = bCompress ? "arj a -v" : "arj e -v";
cmd += m_TotalBytes; // 分卷大小
cmd += " ..\\" + ArjPath + "\\" + ArjFile + " ";
cmd += bCompress ? "..\\" + TempPath + "\\*.* " : "..\\" + TempPath + "\\ ";
cmd += "-y -jm\n";
f.WriteString(cmd);
f.WriteString("dir > " + ExitFlag + "\n"); // 完成旗標檔
f.Close();
}
void CMyCompress::RunBat(CString BatPath, CString BatName, CString ExitFlag) {
STARTUPINFO si = {sizeof(si)}; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
CreateProcess(BatPath + BatName, NULL, NULL, NULL, FALSE,
CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
DeleteFile(ExitFlag); SetTimer(1, 100, NULL); m_bSearching = TRUE;
// OnTimer 每 100ms 檢查 ExitFlag 是否存在
// 存在 → KillTimer → TerminateProcess/CloseHandle → 後續處理
}
OnTimer:
void CMyCompress::OnTimer(UINT) {
CFile f; if (f.Open(m_ExitFlag, CFile::modeRead)) { m_bSearching = FALSE; f.Close(); }
}
DeleteTreeWin32 無對應 API,自行實作:
BOOL DeleteTree(CString Dir) {
return PreRemoveDirectory(Dir) && RemoveDirectory(Dir);
}
BOOL PreRemoveDirectory(CString Dir) {
SetCurrentDirectory(Dir);
HANDLE h = FindFirstFile("*.*", &fd);
if (h != INVALID_HANDLE_VALUE) {
do {
if (fd.cFileName[0]=='.') continue;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
PreRemoveDirectory(fd.cFileName), RemoveDirectory(fd.cFileName);
else
DeleteFile(fd.cFileName);
} while (FindNextFile(h, &fd));
FindClose(h);
}
SetCurrentDirectory(m_OriginalDir);
return TRUE;
}
優於進程調用:無外部相依、效率高、易維護、可精細錯誤處理。
// 列舉可移動磁碟
GetLogicalDriveStrings → GetDriveType == DRIVE_REMOVABLE → 加入下拉清單
// 查詢容量/序號/清空
GetDiskFreeSpace → 總/可用空間
GetVolumeInformation → 序號、檔案系統、磁碟標籤
PreRemoveDirectory(Drive) → 清空內容 (含寫保護檢查對話框)
SetVolumeLabel(Drive, NewLabel) → 設定磁碟標籤
| 功能 | 內部函式 | 進程調用 | 建議 |
|---|---|---|---|
| 壓縮/解壓 | 演算法複雜、維護成本高 | 成熟工具 (ARJ/7z)、一行命令 | 進程調用 |
| 刪除目錄樹 | API 簡單、可控 | 需外部命令、參數麻煩 | 內部函式 |
| 磁碟資訊 | Win32 API 完整 | 無標準命令列工具 | 內部函式 |
原則:**演算法複雜/有成熟工具 → 進程調用;OS API 完整/邏輯簡單 → 內部函式**。