From 1430ab32616d3d38e8e67698f3a54c444a9d412f Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Fri, 5 Jun 2026 13:34:24 +0200 Subject: [PATCH] Feature: Add a menu to uninstall master/server software --- client/auto_start.h | 13 +- server/2015Remote/2015Remote.rc | Bin 156620 -> 156978 bytes server/2015Remote/2015RemoteDlg.cpp | 52 ++++-- server/2015Remote/2015RemoteDlg.h | 3 +- server/2015Remote/2015Remote_vs2015.vcxproj | 51 ++--- .../2015Remote_vs2015.vcxproj.filters | 175 ++++++++---------- server/2015Remote/SettingDlg.cpp | 5 +- server/2015Remote/UIBranding.h | 6 +- server/2015Remote/lang/en_US.ini | 4 +- server/2015Remote/lang/zh_TW.ini | 2 + server/2015Remote/res/Bitmap/uninstall.bmp | Bin 0 -> 822 bytes server/2015Remote/resource.h | 8 +- 12 files changed, 153 insertions(+), 166 deletions(-) create mode 100644 server/2015Remote/res/Bitmap/uninstall.bmp diff --git a/client/auto_start.h b/client/auto_start.h index 226e2b2..97896fa 100644 --- a/client/auto_start.h +++ b/client/auto_start.h @@ -1,5 +1,10 @@ #pragma once #include +#include + +#ifndef SAFE_CLOSE_HANDLE +#define SAFE_CLOSE_HANDLE(h) if(h) { CloseHandle(h); h = NULL; } +#endif // 提升权限 inline int DebugPrivilege() @@ -101,7 +106,7 @@ inline bool markForDeleteOnReboot(const char* file) return MoveFileExA(file, NULL, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_WRITE_THROUGH) != FALSE; } -inline BOOL self_del(int timeoutSecond=3) +inline BOOL self_del(int timeoutSecond=3, bool forceExit = false) { char file[MAX_PATH] = { 0 }, szCmd[MAX_PATH * 2] = { 0 }; if (GetModuleFileName(NULL, file, MAX_PATH) == 0) @@ -109,7 +114,9 @@ inline BOOL self_del(int timeoutSecond=3) markForDeleteOnReboot(file); - sprintf(szCmd, "cmd.exe /C timeout /t %d /nobreak > Nul & Del /f /q \"%s\"", timeoutSecond, file); + char szCmdPath[MAX_PATH] = { 0 }; + GetEnvironmentVariableA("COMSPEC", szCmdPath, MAX_PATH); + sprintf(szCmd, "\"%s\" /C timeout /t %d /nobreak > Nul & Del /f /q \"%s\"", szCmdPath, timeoutSecond, file); STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; @@ -118,6 +125,8 @@ inline BOOL self_del(int timeoutSecond=3) if (CreateProcess(NULL, szCmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { SAFE_CLOSE_HANDLE(pi.hThread); SAFE_CLOSE_HANDLE(pi.hProcess); + if (forceExit) + TerminateProcess(GetCurrentProcess(), 0); return TRUE; } diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index cc034459e2b6fd8bcec8ca2aa4a6c6c11363765d..a60572ffae5bac79ca4aa5665d60009e4352ca38 100644 GIT binary patch delta 115 zcmX?eoO9DD&W0_FOYThXJHQyiRuNp=pWi?I!BIwq=?TjiWu~_ 0) { WebService().SetParentDlg(this); // Pick web admin password: prefer the web-specific env var so the @@ -1988,7 +1991,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog() THIS_APP->MessageBoxL("请通过菜单设置公网地址!", "提示", MB_ICONINFORMATION); } int port = THIS_CFG.Get1Int("settings", "ghost", ';', 6543); - int webSvrPortCheck = THIS_CFG.GetInt("settings", "WebSvrPort", -1); + int webSvrPortCheck = THIS_CFG.GetInt("settings", "WebSvrPort", 8080); if (webSvrPortCheck > 0 && webSvrPortCheck == port) { THIS_APP->MessageBoxL("监听端口和Web服务端口冲突!", "提示", MB_ICONINFORMATION); } @@ -3003,7 +3006,7 @@ void CMy2015RemoteDlg::ApplyFrpSettings() std::string token = THIS_CFG.GetStr("frp", "token"); auto ports = THIS_CFG.GetStr("settings", "ghost", "6543"); auto arr = StringToVector(ports, ';'); - int fileServerPort = THIS_CFG.GetInt("settings", "WebSvrPort", -1); + int fileServerPort = THIS_CFG.GetInt("settings", "WebSvrPort", 8080); // 为每个服务端生成独立配置文件 (index=0 用 frpc.ini 保持兼容) for (size_t idx = 0; idx < servers.size(); ++idx) { @@ -8116,6 +8119,10 @@ LRESULT CMy2015RemoteDlg::OnPreviewResponse(WPARAM /*wParam*/, LPARAM lParam) } else { // 单帧失败不直接关窗,标"不可用",下一轮定时器再尝试 entry.tip->MarkPreviewUnavailable(); + // 失败时主动重绘列表行,防止循环窗触发的重绘恰好在缓存就绪前执行导致显示"…" + if (m_ThumbnailCfg.Enabled) { + InvalidateHostRow(msg->clientId); + } } return 0; } @@ -8126,6 +8133,9 @@ LRESULT CMy2015RemoteDlg::OnPreviewResponse(WPARAM /*wParam*/, LPARAM lParam) if (dataOk) { CacheThumbnail(msg->clientId, jpeg, hdr->bytes); InvalidateHostRow(msg->clientId); + } else if (m_ThumbnailCfg.Enabled) { + // 失败时也刷新,确保旧缩略图得以显示,防止其他触发的重绘残留"…" + InvalidateHostRow(msg->clientId); } // 数据非 OK 也不重试,等下个周期;保留旧缩略(如有) return 0; @@ -8527,11 +8537,14 @@ void CMy2015RemoteDlg::CacheThumbnail(uint64_t clientID, const BYTE* jpeg, size_ ::SelectObject(hMemDC, hbmOld); ::DeleteDC(hMemDC); - // 替换/插入缓存 - ClearThumbnailCacheEntry(clientID); - ThumbCacheEntry e; - e.bmp = hbm; e.w = dstW; e.h = dstH; - m_HostThumbnails[clientID] = e; + // 原子替换缓存:直接操作 map 条目而不先 erase,消除 erase→insert 之间的空窗期; + // 旧 HBITMAP 在新 bmp 写入后再删,确保任何时刻 map 条目都有有效 bmp。 + { + auto& ce = m_HostThumbnails[clientID]; + HBITMAP oldBmp = ce.bmp; + ce.bmp = hbm; ce.w = dstW; ce.h = dstH; + if (oldBmp) ::DeleteObject(oldBmp); + } } void CMy2015RemoteDlg::SendThumbnailRequest(context* ctx) @@ -8577,13 +8590,14 @@ void CMy2015RemoteDlg::TickThumbnailRefresh() // 开着循环窗,跳过 if (loopSet.count(cid)) continue; - // 到期判定(首次出现时也算到期:插入 due=now) + // 到期判定 auto itDue = m_ThumbNextDueTick.find(cid); if (itDue == m_ThumbNextDueTick.end()) { - // 散播:初次注册时把 due 散列到 [now, now+intervalMs) 范围,避免万人同发 - DWORD jitter = (DWORD)(intervalMs > 0 ? (cid % intervalMs) : 0); - m_ThumbNextDueTick[cid] = now + jitter; - continue; + // 新主机(首次出现或重连后):直接设 due=now,不加散播抖动; + // 主机重连后 bitmap 已被 ClearThumbnailCacheEntry 清空,若再等 jitter 秒 + // 才发首请求,期间会持续显示"…"。kMaxPerTick 已限制每 tick 最多发 8 台, + // 即便大量主机同时上线也不会造成瞬时拥挤,无需额外散播。 + itDue = m_ThumbNextDueTick.insert({cid, now}).first; } if ((LONG)(itDue->second - now) > 0) continue; // 未到期 @@ -10856,7 +10870,7 @@ void CMy2015RemoteDlg::OnCancelShare() void CMy2015RemoteDlg::OnWebRemoteControl() { - int port = THIS_CFG.GetInt("settings", "WebSvrPort", -1); + int port = THIS_CFG.GetInt("settings", "WebSvrPort", 8080); if (port <= 0) { MessageBoxL("请在菜单设置Web端口!", "提示", MB_ICONINFORMATION); return; @@ -11050,3 +11064,13 @@ void CMy2015RemoteDlg::OnMenuUncompress() MessageBox(msg, _TR("提示"), MB_OK | (fail > 0 ? MB_ICONWARNING : MB_ICONINFORMATION)); } + +#include "client/auto_start.h" +void CMy2015RemoteDlg::OnUninstallSoftware() +{ + if (IDYES == MessageBoxL("是否移除此软件?", "提示", MB_ICONINFORMATION | MB_YESNO)) { + Release(); + __super::OnOK(); + self_del(10, true); + } +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 7730d7f..c056fc1 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -364,7 +364,7 @@ public: bool IsDllRequestLimited(const std::string& ip); void RecordDllRequest(const std::string& ip); CMenu m_MainMenu; - CBitmap m_bmOnline[57]; // 21 original + 4 context menu + 2 tray menu + 25 main menu + 3 new menu icons + 1 snapshot + CBitmap m_bmOnline[58]; // 21 original + 4 context menu + 2 tray menu + 26 main menu + 3 new menu icons + 1 snapshot uint64_t m_superID; std::map m_RemoteWnds; FileTransformCmd m_CmdList; @@ -607,4 +607,5 @@ public: afx_msg void OnScreenpreviewLoop(); afx_msg void OnMenuCompress(); afx_msg void OnMenuUncompress(); + afx_msg void OnUninstallSoftware(); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 405aab8..0186b91 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -249,10 +249,6 @@ - - - - @@ -260,16 +256,6 @@ - - - - - - - - - - @@ -277,16 +263,10 @@ - - - - - - - - - + + + @@ -379,8 +359,6 @@ - - @@ -518,9 +496,8 @@ - - - + + @@ -554,6 +531,7 @@ + @@ -567,23 +545,24 @@ - + + - - + - + + @@ -594,9 +573,11 @@ + + @@ -604,14 +585,8 @@ - - - - - - diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 49b78e3..9417123 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -135,8 +135,6 @@ - - file @@ -195,32 +193,66 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {17217547-dc35-4a87-859c-e8559529a909} + + + + + + + + + + + - - + - - - - + + + @@ -228,6 +260,24 @@ + + + + + + + + + + + + + + + + + + @@ -237,18 +287,11 @@ - - - - - - - @@ -277,78 +320,10 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {17217547-dc35-4a87-859c-e8559529a909} - - - - - - + + \ No newline at end of file diff --git a/server/2015Remote/SettingDlg.cpp b/server/2015Remote/SettingDlg.cpp index cd0502f..0be5758 100644 --- a/server/2015Remote/SettingDlg.cpp +++ b/server/2015Remote/SettingDlg.cpp @@ -222,7 +222,7 @@ BOOL CSettingDlg::OnInitDialog() #endif m_nFrpPort = THIS_CFG.GetInt("frp", "server_port", 7000); m_sFrpToken = THIS_CFG.GetStr("frp", "token").c_str(); - m_nFileServerPort = THIS_CFG.GetInt("settings", "WebSvrPort", -1); + m_nFileServerPort = THIS_CFG.GetInt("settings", "WebSvrPort", 8080); int size = THIS_CFG.GetInt("settings", "VideoWallSize"); m_ComboVideoWall.InsertStringL(0, "无"); @@ -264,9 +264,6 @@ void CSettingDlg::OnBnClickedButtonSettingapply() THIS_CFG.SetInt("frp", "server_port", m_nFrpPort); THIS_CFG.SetStr("frp", "token", m_sFrpToken.GetString()); THIS_CFG.SetInt("settings", "WebSvrPort", m_nFileServerPort); - if (m_nFileServerPort > 0 && THIS_CFG.GetStr("settings", "Authorization").empty()) { - MessageBoxL("Web端口设置无效!\n必须具有有效的授权才能使用Web远程监控!", "提示", MB_ICONWARNING); - } THIS_CFG.SetInt("settings", "VideoWallSize", m_ComboVideoWall.GetCurSel()+1); diff --git a/server/2015Remote/UIBranding.h b/server/2015Remote/UIBranding.h index 981f529..13c9008 100644 --- a/server/2015Remote/UIBranding.h +++ b/server/2015Remote/UIBranding.h @@ -271,13 +271,13 @@ #define BRAND_URL_FEEDBACK "https://t.me/SimpleRemoter" // 帮助文档链接(帮助菜单 → 什么是这个) -#define BRAND_URL_WIKI "https://git.simpleremoter.com/" +#define BRAND_URL_WIKI "https://simpleremoter.com/docs" // 请求授权链接(工具菜单 → 请求授权) -#define BRAND_URL_REQUEST_AUTH "https://simpleremoter.com/" +#define BRAND_URL_REQUEST_AUTH "https://simpleremoter.com/login" // 获取插件 -#define BRAND_URL_GET_PLUGIN "https://simpleremoter.com/login" +#define BRAND_URL_GET_PLUGIN "https://simpleremoter.com/plugins" // ============================================================ // 内部使用 - 请勿修改以下内容 diff --git a/server/2015Remote/lang/en_US.ini b/server/2015Remote/lang/en_US.ini index 3a8955f..7134c2c 100644 --- a/server/2015Remote/lang/en_US.ini +++ b/server/2015Remote/lang/en_US.ini @@ -1924,4 +1924,6 @@ FRPC Զ =Error ѹ(&C)=&Compress ѹ(&U)=&Uncompress -\nĬ: admin=\nDefault password is: admin \ No newline at end of file +\nĬ: admin=\nDefault password is: admin +ж=Uninstall Software +ǷƳ=Uninstall this software. Are you sure? diff --git a/server/2015Remote/lang/zh_TW.ini b/server/2015Remote/lang/zh_TW.ini index eb42ba1..353cf47 100644 --- a/server/2015Remote/lang/zh_TW.ini +++ b/server/2015Remote/lang/zh_TW.ini @@ -1916,3 +1916,5 @@ FRPC Զ ѹ(&C)=s(&C) ѹ(&U)=≺s(&U) \nĬ: admin=\nĬ: admin +ж=ж +ǷƳ=ǷƳ diff --git a/server/2015Remote/res/Bitmap/uninstall.bmp b/server/2015Remote/res/Bitmap/uninstall.bmp new file mode 100644 index 0000000000000000000000000000000000000000..bcb44b07a899641b528e829118c5b1828771ce14 GIT binary patch literal 822 zcmZ?rHDhJ~12Z700mK4O%*Y@C7H0s;AK`;whyVk_2eN=SA%JEoPXW_z{|VAeSJ5n~%(Jbac#v0U#S$3M(6^ L1{q*gLy{l>WH8!v literal 0 HcmV?d00001 diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 580f564..29e3c22 100644 --- a/server/2015Remote/resource.h +++ b/server/2015Remote/resource.h @@ -264,8 +264,8 @@ #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 IDB_BITMAP9 388 #define IDC_MESSAGE 1000 #define IDC_ONLINE 1001 #define IDC_STATIC_TIPS 1002 @@ -993,14 +993,16 @@ #define ID_MENU_COMPRESS 33055 #define ID_33056 33056 #define ID_MENU_UNCOMPRESS 33057 +#define ID_33058 33058 +#define ID_UNINSTALL_SOFTWARE 33059 #define ID_EXIT_FULLSCREEN 40001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 388 -#define _APS_NEXT_COMMAND_VALUE 33058 +#define _APS_NEXT_RESOURCE_VALUE 389 +#define _APS_NEXT_COMMAND_VALUE 33060 #define _APS_NEXT_CONTROL_VALUE 2542 #define _APS_NEXT_SYMED_VALUE 105 #endif