Feature: add menu-driven compress/extract via custom file+folder picker
This commit is contained in:
Binary file not shown.
@@ -637,7 +637,8 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogLangEx(CMy2015RemoteDl
|
||||
m_bmOnline[52].LoadBitmap(IDB_BITMAP_WEBDESKTOP);
|
||||
m_bmOnline[53].LoadBitmap(IDB_BITMAP_PLUGINCONFIG);
|
||||
m_bmOnline[54].LoadBitmap(IDB_BITMAP_SNAPSHOT); // "播放快照" 菜单的眼睛图标
|
||||
|
||||
m_bmOnline[55].LoadBitmap(IDB_BITMAP_COMPRESS);
|
||||
m_bmOnline[56].LoadBitmap(IDB_BITMAP_UNCOMPRESS);
|
||||
for (int i = 0; i < PAYLOAD_MAXTYPE; i++) {
|
||||
m_ServerDLL[i] = nullptr;
|
||||
m_ServerBin[i] = nullptr;
|
||||
@@ -919,6 +920,8 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
|
||||
ON_COMMAND(ID_WEB_REMOTE_CONTROL, &CMy2015RemoteDlg::OnWebRemoteControl)
|
||||
ON_COMMAND(ID_PROXY_PORT_AUTORUN, &CMy2015RemoteDlg::OnProxyPortAutorun)
|
||||
ON_COMMAND(ID_SCREENPREVIEW_LOOP, &CMy2015RemoteDlg::OnScreenpreviewLoop)
|
||||
ON_COMMAND(ID_MENU_COMPRESS, &CMy2015RemoteDlg::OnMenuCompress)
|
||||
ON_COMMAND(ID_MENU_UNCOMPRESS, &CMy2015RemoteDlg::OnMenuUncompress)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
|
||||
@@ -989,6 +992,8 @@ VOID CMy2015RemoteDlg::CreateSolidMenu()
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_MAIN_NETWORK, MF_BYCOMMAND, &m_bmOnline[29], &m_bmOnline[29]);
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_TRIGGER_SETTINGS, MF_BYCOMMAND, &m_bmOnline[51], &m_bmOnline[51]);
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_MAIN_EXIT, MF_BYCOMMAND, &m_bmOnline[26], &m_bmOnline[26]);
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_MENU_COMPRESS, MF_BYCOMMAND, &m_bmOnline[55], &m_bmOnline[55]);
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_MENU_UNCOMPRESS, MF_BYCOMMAND, &m_bmOnline[56], &m_bmOnline[56]);
|
||||
// Tools menu
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_TOOL_INPUT_PASSWORD, MF_BYCOMMAND, &m_bmOnline[30], &m_bmOnline[30]);
|
||||
m_MainMenu.SetMenuItemBitmaps(ID_TOOL_IMPORT_LICENSE, MF_BYCOMMAND, &m_bmOnline[31], &m_bmOnline[31]);
|
||||
@@ -10915,3 +10920,112 @@ void CMy2015RemoteDlg::OnScreenpreviewLoop()
|
||||
ShowMessage(_TR("提示"), msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== ZSTA 压缩 / 解压 =====
|
||||
#include "ZstdArchive.h"
|
||||
#include "ZstaPickerDlg.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// 把一组源路径压缩为单个 .zsta 文件(弹出保存对话框选择输出)
|
||||
// 调用者只负责传路径,输出路径与压缩过程由本函数处理
|
||||
void CompressPathsToZsta(CWnd* parent, const std::vector<std::string>& srcPaths)
|
||||
{
|
||||
if (srcPaths.empty()) return;
|
||||
|
||||
// 默认输出文件名:第一个源的 basename 或 archive
|
||||
std::string defaultName;
|
||||
{
|
||||
std::string first = srcPaths[0];
|
||||
while (!first.empty() && (first.back() == '/' || first.back() == '\\'))
|
||||
first.pop_back();
|
||||
size_t pos = first.find_last_of("/\\");
|
||||
defaultName = (pos == std::string::npos) ? first : first.substr(pos + 1);
|
||||
if (srcPaths.size() > 1) defaultName = "archive";
|
||||
defaultName += ".zsta";
|
||||
}
|
||||
|
||||
CFileDialog saveDlg(FALSE, _T("zsta"), CString(defaultName.c_str()),
|
||||
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
|
||||
_T("ZSTA Files (*.zsta)|*.zsta|All Files (*.*)|*.*||"),
|
||||
parent);
|
||||
CString saveTitle = _TR("选择压缩输出文件");
|
||||
saveDlg.m_ofn.lpstrTitle = saveTitle;
|
||||
if (saveDlg.DoModal() != IDOK) return;
|
||||
|
||||
std::string outPath = std::string(CT2A(saveDlg.GetPathName().GetString()));
|
||||
auto err = zsta::CZstdArchive::Compress(srcPaths, outPath, 3);
|
||||
if (err == zsta::Error::Success) {
|
||||
Mprintf("ZSTA 压缩成功: %u 项 -> %s\n",
|
||||
(unsigned)srcPaths.size(), outPath.c_str());
|
||||
CString msg;
|
||||
msg.FormatL("压缩成功 (%u 项):\n%s",
|
||||
(unsigned)srcPaths.size(), outPath.c_str());
|
||||
parent->MessageBox(msg, _TR("提示"), MB_OK | MB_ICONINFORMATION);
|
||||
} else {
|
||||
Mprintf("ZSTA 压缩失败 [%s]: -> %s\n",
|
||||
zsta::CZstdArchive::GetErrorString(err), outPath.c_str());
|
||||
CString msg;
|
||||
msg.FormatL("压缩失败: %s", zsta::CZstdArchive::GetErrorString(err));
|
||||
parent->MessageBox(msg, _TR("错误"), MB_OK | MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CMy2015RemoteDlg::OnMenuCompress()
|
||||
{
|
||||
CZstaPickerDlg picker(this);
|
||||
if (picker.DoModal() != IDOK) return;
|
||||
if (picker.m_Paths.empty()) {
|
||||
MessageBoxL("未选择任何文件或文件夹", "提示", MB_OK | MB_ICONINFORMATION);
|
||||
return;
|
||||
}
|
||||
CompressPathsToZsta(this, picker.m_Paths);
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::OnMenuUncompress()
|
||||
{
|
||||
const DWORD MAX_BUF = 64 * 1024;
|
||||
std::vector<TCHAR> buf(MAX_BUF, 0);
|
||||
CFileDialog dlg(TRUE, _T("zsta"), NULL,
|
||||
OFN_ALLOWMULTISELECT | OFN_EXPLORER |
|
||||
OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
|
||||
_T("ZSTA Files (*.zsta)|*.zsta|All Files (*.*)|*.*||"), this);
|
||||
dlg.m_ofn.lpstrFile = buf.data();
|
||||
dlg.m_ofn.nMaxFile = MAX_BUF;
|
||||
CString title = _TR("请选择要解压的 ZSTA 文件 (可多选)");
|
||||
dlg.m_ofn.lpstrTitle = title;
|
||||
if (dlg.DoModal() != IDOK) return;
|
||||
|
||||
int ok = 0, fail = 0;
|
||||
POSITION pos = dlg.GetStartPosition();
|
||||
while (pos) {
|
||||
CString cpath = dlg.GetNextPathName(pos);
|
||||
std::string src(CT2A(cpath.GetString()));
|
||||
|
||||
// 目标目录:去掉 .zsta 后缀;若无该后缀则追加 _extract
|
||||
std::string dst;
|
||||
if (src.size() >= 5) {
|
||||
std::string ext = src.substr(src.size() - 5);
|
||||
for (char& c : ext) c = (char)tolower((unsigned char)c);
|
||||
if (ext == ".zsta") dst = src.substr(0, src.size() - 5);
|
||||
}
|
||||
if (dst.empty()) dst = src + "_extract";
|
||||
|
||||
auto err = zsta::CZstdArchive::Extract(src, dst);
|
||||
if (err == zsta::Error::Success) {
|
||||
++ok;
|
||||
Mprintf("ZSTA 解压成功: %s -> %s\n", src.c_str(), dst.c_str());
|
||||
} else {
|
||||
++fail;
|
||||
Mprintf("ZSTA 解压失败 [%s]: %s\n",
|
||||
zsta::CZstdArchive::GetErrorString(err), src.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
CString msg;
|
||||
msg.FormatL("解压完成: 成功 %d, 失败 %d", ok, fail);
|
||||
MessageBox(msg, _TR("提示"),
|
||||
MB_OK | (fail > 0 ? MB_ICONWARNING : MB_ICONINFORMATION));
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ public:
|
||||
bool IsDllRequestLimited(const std::string& ip);
|
||||
void RecordDllRequest(const std::string& ip);
|
||||
CMenu m_MainMenu;
|
||||
CBitmap m_bmOnline[55]; // 21 original + 4 context menu + 2 tray menu + 23 main menu + 3 new menu icons + 1 snapshot
|
||||
CBitmap m_bmOnline[57]; // 21 original + 4 context menu + 2 tray menu + 25 main menu + 3 new menu icons + 1 snapshot
|
||||
uint64_t m_superID;
|
||||
std::map<HWND, CDialogBase *> m_RemoteWnds;
|
||||
FileTransformCmd m_CmdList;
|
||||
@@ -604,4 +604,6 @@ public:
|
||||
afx_msg void OnWebRemoteControl();
|
||||
afx_msg void OnProxyPortAutorun();
|
||||
afx_msg void OnScreenpreviewLoop();
|
||||
afx_msg void OnMenuCompress();
|
||||
afx_msg void OnMenuUncompress();
|
||||
};
|
||||
|
||||
@@ -334,6 +334,7 @@
|
||||
<ClInclude Include="HideScreenSpyDlg.h" />
|
||||
<ClInclude Include="HostInfo.h" />
|
||||
<ClInclude Include="InputDlg.h" />
|
||||
<ClInclude Include="ZstaPickerDlg.h" />
|
||||
<ClInclude Include="IOCPKCPServer.h" />
|
||||
<ClInclude Include="IOCPServer.h" />
|
||||
<ClInclude Include="IOCPUDPServer.h" />
|
||||
@@ -459,6 +460,7 @@
|
||||
<ClCompile Include="file\CFileTransferModeDlg.cpp" />
|
||||
<ClCompile Include="HideScreenSpyDlg.cpp" />
|
||||
<ClCompile Include="InputDlg.cpp" />
|
||||
<ClCompile Include="ZstaPickerDlg.cpp" />
|
||||
<ClCompile Include="IOCPKCPServer.cpp" />
|
||||
<ClCompile Include="IOCPServer.cpp" />
|
||||
<ClCompile Include="IOCPUDPServer.cpp" />
|
||||
@@ -525,7 +527,9 @@
|
||||
<Image Include="res\Bitmap\AuthGen.bmp" />
|
||||
<Image Include="res\Bitmap\authorize.bmp" />
|
||||
<Image Include="res\Bitmap\Backup.bmp" />
|
||||
<Image Include="res\bitmap\bitmap9.bmp" />
|
||||
<Image Include="res\Bitmap\CancelShare.bmp" />
|
||||
<Image Include="res\bitmap\compress.bmp" />
|
||||
<Image Include="res\Bitmap\delete.bmp" />
|
||||
<Image Include="res\Bitmap\DxgiDesktop.bmp" />
|
||||
<Image Include="res\Bitmap\EditGroup.bmp" />
|
||||
@@ -569,6 +573,7 @@
|
||||
<Image Include="res\Bitmap\Trial.bmp" />
|
||||
<Image Include="res\Bitmap\Trigger.bmp" />
|
||||
<Image Include="res\Bitmap\unauthorize.bmp" />
|
||||
<Image Include="res\bitmap\uncompress.bmp" />
|
||||
<Image Include="res\Bitmap\update.bmp" />
|
||||
<Image Include="res\Bitmap\VirtualDesktop.bmp" />
|
||||
<Image Include="res\Bitmap\Wallet.bmp" />
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<ClCompile Include="FileTransferModeDlg.cpp" />
|
||||
<ClCompile Include="HideScreenSpyDlg.cpp" />
|
||||
<ClCompile Include="InputDlg.cpp" />
|
||||
<ClCompile Include="ZstaPickerDlg.cpp" />
|
||||
<ClCompile Include="IOCPServer.cpp" />
|
||||
<ClCompile Include="KeyBoardDlg.cpp" />
|
||||
<ClCompile Include="Loader.c" />
|
||||
@@ -107,6 +108,7 @@
|
||||
<ClInclude Include="FileTransferModeDlg.h" />
|
||||
<ClInclude Include="HideScreenSpyDlg.h" />
|
||||
<ClInclude Include="InputDlg.h" />
|
||||
<ClInclude Include="ZstaPickerDlg.h" />
|
||||
<ClInclude Include="IOCPServer.h" />
|
||||
<ClInclude Include="KeyBoardDlg.h" />
|
||||
<ClInclude Include="proxy\HPSocket.h" />
|
||||
@@ -275,6 +277,9 @@
|
||||
<Image Include="res\Bitmap\Trigger.bmp" />
|
||||
<Image Include="res\Bitmap\WebDesktop.bmp" />
|
||||
<Image Include="res\Bitmap\PluginConfig.bmp" />
|
||||
<Image Include="res\bitmap\bitmap9.bmp" />
|
||||
<Image Include="res\bitmap\compress.bmp" />
|
||||
<Image Include="res\bitmap\uncompress.bmp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\Release\ghost.exe" />
|
||||
|
||||
260
server/2015Remote/ZstaPickerDlg.cpp
Normal file
260
server/2015Remote/ZstaPickerDlg.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
#include "stdafx.h"
|
||||
#include "ZstaPickerDlg.h"
|
||||
#include "LangManager.h"
|
||||
#include <shobjidl.h>
|
||||
#include <atlconv.h>
|
||||
#include <algorithm>
|
||||
|
||||
#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<BYTE>& 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<TCHAR> 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<int> indices;
|
||||
POSITION pos = m_List.GetFirstSelectedItemPosition();
|
||||
while (pos) indices.push_back(m_List.GetNextSelectedItem(pos));
|
||||
|
||||
std::sort(indices.begin(), indices.end(), std::greater<int>());
|
||||
for (int idx : indices) {
|
||||
if (idx >= 0 && idx < (int)m_Paths.size()) {
|
||||
m_Paths.erase(m_Paths.begin() + idx);
|
||||
}
|
||||
}
|
||||
RefreshList();
|
||||
}
|
||||
52
server/2015Remote/ZstaPickerDlg.h
Normal file
52
server/2015Remote/ZstaPickerDlg.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <afxwin.h>
|
||||
#include <afxcmn.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// 让用户在同一个对话框里累加要压缩的"文件 + 文件夹"组合:
|
||||
// [添加文件...] 调出多选文件对话框
|
||||
// [添加文件夹...] 调出多选文件夹对话框 (IFileOpenDialog + FOS_PICKFOLDERS)
|
||||
// [移除选中] 从列表里删除
|
||||
// DoModal() 返回 IDOK 时,m_Paths 即为结果 (ANSI/MBCS 路径,与 ZSTA 管道一致)。
|
||||
class CZstaPickerDlg : public CDialog
|
||||
{
|
||||
public:
|
||||
explicit CZstaPickerDlg(CWnd* parent = nullptr);
|
||||
|
||||
virtual INT_PTR DoModal();
|
||||
|
||||
std::vector<std::string> m_Paths;
|
||||
|
||||
protected:
|
||||
virtual BOOL OnInitDialog();
|
||||
|
||||
afx_msg void OnAddFiles();
|
||||
afx_msg void OnAddFolders();
|
||||
afx_msg void OnRemove();
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
private:
|
||||
enum CtrlId {
|
||||
IDC_ZSTA_LIST = 1001,
|
||||
IDC_ZSTA_ADDFILES = 1002,
|
||||
IDC_ZSTA_ADDFOLDERS = 1003,
|
||||
IDC_ZSTA_REMOVE = 1004,
|
||||
};
|
||||
|
||||
CListCtrl m_List;
|
||||
CButton m_BtnAddFiles;
|
||||
CButton m_BtnAddFolders;
|
||||
CButton m_BtnRemove;
|
||||
CButton m_BtnOK;
|
||||
CButton m_BtnCancel;
|
||||
|
||||
std::vector<BYTE> m_Template; // in-memory DLGTEMPLATE bytes
|
||||
|
||||
void AddPath(const std::string& path);
|
||||
void RefreshList();
|
||||
void LayoutControls(int cx, int cy);
|
||||
};
|
||||
@@ -1894,3 +1894,33 @@ FRPC Զ
|
||||
创建AVI文件失败=Create AVI file failed
|
||||
启用 H264 硬编码=Enable HW H264 Encoding
|
||||
启用 AV1 硬编码=Enable HW AV1 Encoding
|
||||
; ZSTA Compress / Picker Dialog - English Translation
|
||||
; Format: Simplified Chinese=English
|
||||
|
||||
; --- Picker dialog (CZstaPickerDlg) ---
|
||||
选择要压缩的文件 / 文件夹=Select Files / Folders to Compress
|
||||
添加文件...=Add Files...
|
||||
添加文件夹...=Add Folders...
|
||||
移除选中=Remove Selected
|
||||
类型=Type
|
||||
路径=Path
|
||||
文件=File
|
||||
文件夹=Folder
|
||||
选择文件 (可多选)=Select Files (multi-select)
|
||||
选择文件夹 (可多选)=Select Folders (multi-select)
|
||||
|
||||
; --- Compress / Extract handlers (CMy2015RemoteDlg) ---
|
||||
未选择任何文件或文件夹=No file or folder selected
|
||||
选择压缩输出文件=Choose Output Archive
|
||||
请选择要解压的 ZSTA 文件 (可多选)=Choose ZSTA File(s) to Extract (multi-select)
|
||||
压缩成功 (%u 项):\n%s=Compression succeeded (%u item(s)):\n%s
|
||||
压缩失败: %s=Compression failed: %s
|
||||
解压完成: 成功 %d, 失败 %d=Extraction complete: %d succeeded, %d failed
|
||||
|
||||
; --- Common (likely already present in en_US.ini; included for completeness) ---
|
||||
确定=OK
|
||||
取消=Cancel
|
||||
提示=Notice
|
||||
错误=Error
|
||||
压缩(&C)=&Compress
|
||||
解压缩(&U)=&Uncompress
|
||||
|
||||
@@ -1885,3 +1885,33 @@ FRPC Զ
|
||||
创建AVI文件失败=创建AVI文件失败
|
||||
启用 H264 硬编码=启用 H264 硬编码
|
||||
启用 AV1 硬编码=启用 AV1 硬编码
|
||||
; ZSTA Compress / Picker Dialog - Traditional Chinese Translation
|
||||
; Format: Simplified Chinese=Traditional Chinese
|
||||
|
||||
; --- Picker dialog (CZstaPickerDlg) ---
|
||||
选择要压缩的文件 / 文件夹=選擇要壓縮的檔案 / 資料夾
|
||||
添加文件...=新增檔案...
|
||||
添加文件夹...=新增資料夾...
|
||||
移除选中=移除選取項
|
||||
类型=類型
|
||||
路径=路徑
|
||||
文件=檔案
|
||||
文件夹=資料夾
|
||||
选择文件 (可多选)=選擇檔案 (可多選)
|
||||
选择文件夹 (可多选)=選擇資料夾 (可多選)
|
||||
|
||||
; --- Compress / Extract handlers (CMy2015RemoteDlg) ---
|
||||
未选择任何文件或文件夹=未選擇任何檔案或資料夾
|
||||
选择压缩输出文件=選擇壓縮輸出檔案
|
||||
请选择要解压的 ZSTA 文件 (可多选)=請選擇要解壓縮的 ZSTA 檔案 (可多選)
|
||||
压缩成功 (%u 项):\n%s=壓縮成功 (%u 項):\n%s
|
||||
压缩失败: %s=壓縮失敗: %s
|
||||
解压完成: 成功 %d, 失败 %d=解壓縮完成: 成功 %d, 失敗 %d
|
||||
|
||||
; --- Common (likely already present in zh_TW.ini; included for completeness) ---
|
||||
确定=確定
|
||||
取消=取消
|
||||
提示=提示
|
||||
错误=錯誤
|
||||
压缩(&C)=壓縮(&C)
|
||||
解压缩(&U)=解壓縮(&U)
|
||||
|
||||
BIN
server/2015Remote/res/Bitmap/compress.bmp
Normal file
BIN
server/2015Remote/res/Bitmap/compress.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 822 B |
BIN
server/2015Remote/res/Bitmap/uncompress.bmp
Normal file
BIN
server/2015Remote/res/Bitmap/uncompress.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 822 B |
@@ -263,6 +263,9 @@
|
||||
#define IDR_WEB_XTERM_CSS 383
|
||||
#define IDR_WEB_XTERM_FIT_JS 384
|
||||
#define IDR_WEB_INDEX_HTML 385
|
||||
#define IDB_BITMAP_COMPRESS 386
|
||||
#define IDB_BITMAP9 387
|
||||
#define IDB_BITMAP_UNCOMPRESS 387
|
||||
#define IDC_MESSAGE 1000
|
||||
#define IDC_ONLINE 1001
|
||||
#define IDC_STATIC_TIPS 1002
|
||||
@@ -985,14 +988,19 @@
|
||||
#define ID_PARAM_THUMBNAIL_PREVIEW 33050
|
||||
#define ID_LICENSE_AUTO_FRP 33051
|
||||
#define ID_LICENSE_REVOKE_FRP 33052
|
||||
#define ID_Menu 33053
|
||||
#define ID_33054 33054
|
||||
#define ID_MENU_COMPRESS 33055
|
||||
#define ID_33056 33056
|
||||
#define ID_MENU_UNCOMPRESS 33057
|
||||
#define ID_EXIT_FULLSCREEN 40001
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 386
|
||||
#define _APS_NEXT_COMMAND_VALUE 33053
|
||||
#define _APS_NEXT_RESOURCE_VALUE 388
|
||||
#define _APS_NEXT_COMMAND_VALUE 33058
|
||||
#define _APS_NEXT_CONTROL_VALUE 2542
|
||||
#define _APS_NEXT_SYMED_VALUE 105
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user