#include "stdafx.h" #include "ZstaPickerDlg.h" #include "LangManager.h" #include #include #include #ifdef _DEBUG #define new DEBUG_NEW #endif namespace { bool IsDirectoryPath(const std::string& p) { DWORD attr = GetFileAttributesA(p.c_str()); return (attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY); } // 构造一个无控件的 DLGTEMPLATE:cdit=0,控件由 OnInitDialog 动态创建。 void BuildDialogTemplate(std::vector& out, LPCWSTR caption, short cx, short cy) { out.clear(); auto append = [&](const void* p, size_t n) { const BYTE* b = (const BYTE*)p; out.insert(out.end(), b, b + n); }; auto appendW = [&](WORD v) { out.push_back((BYTE)(v & 0xFF)); out.push_back((BYTE)((v >> 8) & 0xFF)); }; auto appendWStr = [&](LPCWSTR s) { size_t n = wcslen(s); append(s, (n + 1) * sizeof(WCHAR)); }; DLGTEMPLATE dt = { 0 }; dt.style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME; dt.dwExtendedStyle = 0; dt.cdit = 0; dt.x = 0; dt.y = 0; dt.cx = cx; dt.cy = cy; append(&dt, sizeof(dt)); appendW(0); // no menu appendW(0); // default dialog class appendWStr(caption); // caption appendW(8); // font point size appendWStr(L"MS Shell Dlg"); // typeface while (out.size() % 4) out.push_back(0); // DWORD align } } // namespace CZstaPickerDlg::CZstaPickerDlg(CWnd* parent) : CDialog((LPCTSTR)NULL, parent) { } BEGIN_MESSAGE_MAP(CZstaPickerDlg, CDialog) ON_BN_CLICKED(IDC_ZSTA_ADDFILES, &CZstaPickerDlg::OnAddFiles) ON_BN_CLICKED(IDC_ZSTA_ADDFOLDERS, &CZstaPickerDlg::OnAddFolders) ON_BN_CLICKED(IDC_ZSTA_REMOVE, &CZstaPickerDlg::OnRemove) ON_WM_SIZE() END_MESSAGE_MAP() INT_PTR CZstaPickerDlg::DoModal() { CString title = _TR("选择要压缩的文件 / 文件夹"); USES_CONVERSION; BuildDialogTemplate(m_Template, T2CW(title), 360, 220); InitModalIndirect((LPCDLGTEMPLATE)m_Template.data()); return CDialog::DoModal(); } BOOL CZstaPickerDlg::OnInitDialog() { CDialog::OnInitDialog(); CRect cli; GetClientRect(&cli); // 占位 rect,真正布局在 LayoutControls 里 CRect r0(0, 0, 10, 10); m_List.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | LVS_REPORT | LVS_SHOWSELALWAYS, r0, this, IDC_ZSTA_LIST); m_List.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); m_List.InsertColumn(0, _TR("类型"), LVCFMT_LEFT, 60); m_List.InsertColumn(1, _TR("路径"), LVCFMT_LEFT, 400); auto mkBtn = [&](CButton& b, LPCTSTR text, int id, DWORD extra = 0) { b.Create(text, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | extra, r0, this, id); }; mkBtn(m_BtnAddFiles, _TR("添加文件..."), IDC_ZSTA_ADDFILES); mkBtn(m_BtnAddFolders, _TR("添加文件夹..."), IDC_ZSTA_ADDFOLDERS); mkBtn(m_BtnRemove, _TR("移除选中"), IDC_ZSTA_REMOVE); mkBtn(m_BtnOK, _TR("确定"), IDOK, BS_DEFPUSHBUTTON); mkBtn(m_BtnCancel, _TR("取消"), IDCANCEL); // 子控件继承对话框的字体 (DS_SETFONT) HFONT hFont = (HFONT)::SendMessage(GetSafeHwnd(), WM_GETFONT, 0, 0); if (hFont) { m_List.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); m_BtnAddFiles.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); m_BtnAddFolders.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); m_BtnRemove.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); m_BtnOK.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); m_BtnCancel.SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); } LayoutControls(cli.Width(), cli.Height()); RefreshList(); return TRUE; } void CZstaPickerDlg::OnSize(UINT nType, int cx, int cy) { CDialog::OnSize(nType, cx, cy); if (m_List.GetSafeHwnd()) LayoutControls(cx, cy); } void CZstaPickerDlg::LayoutControls(int cx, int cy) { const int margin = 10; const int btnW = 120; const int btnH = 26; const int gap = 6; int listRight = cx - margin - btnW - margin; if (listRight < margin + 100) listRight = margin + 100; m_List.MoveWindow(margin, margin, listRight - margin, cy - margin * 2); int x = listRight + margin; int y = margin; m_BtnAddFiles.MoveWindow(x, y, btnW, btnH); y += btnH + gap; m_BtnAddFolders.MoveWindow(x, y, btnW, btnH); y += btnH + gap; m_BtnRemove.MoveWindow(x, y, btnW, btnH); int bottomY = cy - margin - btnH; m_BtnCancel.MoveWindow(x, bottomY, btnW, btnH); m_BtnOK.MoveWindow(x, bottomY - btnH - gap, btnW, btnH); // 让"路径"列填满剩余宽度 if (m_List.GetSafeHwnd()) { CRect lr; m_List.GetClientRect(&lr); int w0 = m_List.GetColumnWidth(0); int w1 = lr.Width() - w0 - GetSystemMetrics(SM_CXVSCROLL) - 4; if (w1 > 100) m_List.SetColumnWidth(1, w1); } } void CZstaPickerDlg::AddPath(const std::string& path) { if (path.empty()) return; if (std::find(m_Paths.begin(), m_Paths.end(), path) == m_Paths.end()) { m_Paths.push_back(path); } } void CZstaPickerDlg::RefreshList() { m_List.DeleteAllItems(); for (size_t i = 0; i < m_Paths.size(); ++i) { bool isDir = IsDirectoryPath(m_Paths[i]); m_List.InsertItem((int)i, isDir ? _TR("文件夹") : _TR("文件")); m_List.SetItemText((int)i, 1, CString(m_Paths[i].c_str())); } } void CZstaPickerDlg::OnAddFiles() { const DWORD MAX_BUF = 64 * 1024; std::vector buf(MAX_BUF, 0); CFileDialog dlg(TRUE, NULL, NULL, OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, _T("All Files (*.*)|*.*||"), this); dlg.m_ofn.lpstrFile = buf.data(); dlg.m_ofn.nMaxFile = MAX_BUF; CString title = _TR("选择文件 (可多选)"); dlg.m_ofn.lpstrTitle = title; if (dlg.DoModal() != IDOK) return; POSITION pos = dlg.GetStartPosition(); while (pos) { CString p = dlg.GetNextPathName(pos); AddPath(std::string(CT2A(p.GetString()))); } RefreshList(); } void CZstaPickerDlg::OnAddFolders() { IFileOpenDialog* pfd = nullptr; HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd)); if (FAILED(hr) || !pfd) return; DWORD flags = 0; pfd->GetOptions(&flags); pfd->SetOptions(flags | FOS_PICKFOLDERS | FOS_ALLOWMULTISELECT | FOS_PATHMUSTEXIST | FOS_FORCEFILESYSTEM); USES_CONVERSION; CString title = _TR("选择文件夹 (可多选)"); pfd->SetTitle(T2CW(title)); if (SUCCEEDED(pfd->Show(GetSafeHwnd()))) { IShellItemArray* psia = nullptr; if (SUCCEEDED(pfd->GetResults(&psia)) && psia) { DWORD count = 0; psia->GetCount(&count); for (DWORD i = 0; i < count; ++i) { IShellItem* psi = nullptr; if (SUCCEEDED(psia->GetItemAt(i, &psi)) && psi) { PWSTR wpath = nullptr; if (SUCCEEDED(psi->GetDisplayName(SIGDN_FILESYSPATH, &wpath)) && wpath) { int n = WideCharToMultiByte(CP_ACP, 0, wpath, -1, NULL, 0, NULL, NULL); if (n > 1) { std::string s(n - 1, '\0'); WideCharToMultiByte(CP_ACP, 0, wpath, -1, &s[0], n, NULL, NULL); AddPath(s); } CoTaskMemFree(wpath); } psi->Release(); } } psia->Release(); } } pfd->Release(); RefreshList(); } void CZstaPickerDlg::OnRemove() { std::vector indices; POSITION pos = m_List.GetFirstSelectedItemPosition(); while (pos) indices.push_back(m_List.GetNextSelectedItem(pos)); std::sort(indices.begin(), indices.end(), std::greater()); for (int idx : indices) { if (idx >= 0 && idx < (int)m_Paths.size()) { m_Paths.erase(m_Paths.begin() + idx); } } RefreshList(); }