diff --git a/client/ScreenManager.cpp b/client/ScreenManager.cpp index e6ff6d8..7b7c939 100644 --- a/client/ScreenManager.cpp +++ b/client/ScreenManager.cpp @@ -457,7 +457,7 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) SendData(szBuffer, sizeof(szBuffer)); break; } - SendClientClipboard(); + SendClientClipboard(ulLength > 1); break; } case COMMAND_SCREEN_SET_CLIPBOARD: { @@ -531,26 +531,48 @@ VOID CScreenManager::UpdateClientClipboard(char *szBuffer, ULONG ulLength) CloseClipboard(); } -VOID CScreenManager::SendClientClipboard() +VOID CScreenManager::SendClientClipboard(BOOL fast) { - if (!::OpenClipboard(NULL)) //打开剪切板设备 - return; - HGLOBAL hGlobal = GetClipboardData(CF_TEXT); //代表着一个内存 - if (hGlobal == NULL) { - ::CloseClipboard(); - return; - } - size_t iPacketLength = GlobalSize(hGlobal) + 1; - char* szClipboardVirtualAddress = (LPSTR) GlobalLock(hGlobal); //锁定 - LPBYTE szBuffer = new BYTE[iPacketLength]; + if (!::OpenClipboard(NULL)) + return; + // 改为获取 Unicode 格式 + HGLOBAL hGlobal = GetClipboardData(CF_UNICODETEXT); + if (hGlobal == NULL) { + ::CloseClipboard(); + return; + } - szBuffer[0] = TOKEN_CLIPBOARD_TEXT; - memcpy(szBuffer + 1, szClipboardVirtualAddress, iPacketLength - 1); - ::GlobalUnlock(hGlobal); - ::CloseClipboard(); - m_ClientObject->Send2Server((char*)szBuffer, iPacketLength); - delete[] szBuffer; + wchar_t* pWideStr = (wchar_t*)GlobalLock(hGlobal); + if (pWideStr == NULL) { + ::CloseClipboard(); + return; + } + + // Unicode 转 UTF-8 + int utf8Len = WideCharToMultiByte(CP_UTF8, 0, pWideStr, -1, NULL, 0, NULL, NULL); + if (utf8Len <= 0) { + GlobalUnlock(hGlobal); + ::CloseClipboard(); + return; + } + + if (fast && utf8Len > 200 * 1024) { + Mprintf("剪切板文本太长, 无法快速拷贝: %d\n", utf8Len); + GlobalUnlock(hGlobal); + ::CloseClipboard(); + return; + } + + LPBYTE szBuffer = new BYTE[utf8Len + 1]; + szBuffer[0] = TOKEN_CLIPBOARD_TEXT; + WideCharToMultiByte(CP_UTF8, 0, pWideStr, -1, (char*)(szBuffer + 1), utf8Len, NULL, NULL); + + GlobalUnlock(hGlobal); + ::CloseClipboard(); + + m_ClientObject->Send2Server((char*)szBuffer, utf8Len + 1); + delete[] szBuffer; } diff --git a/client/ScreenManager.h b/client/ScreenManager.h index 0ed79ec..1bccf67 100644 --- a/client/ScreenManager.h +++ b/client/ScreenManager.h @@ -46,7 +46,7 @@ public: std::string m_DesktopID; BOOL m_bIsWorking; BOOL m_bIsBlockInput; - VOID SendClientClipboard(); + VOID SendClientClipboard(BOOL fast); VOID UpdateClientClipboard(char *szBuffer, ULONG ulLength); std::string m_hash; diff --git a/lib/FileUpload_Libx64.lib b/lib/FileUpload_Libx64.lib index dee75b0..f137a00 100644 Binary files a/lib/FileUpload_Libx64.lib and b/lib/FileUpload_Libx64.lib differ diff --git a/lib/FileUpload_Libx64d.lib b/lib/FileUpload_Libx64d.lib index 9f3ecd3..cf6fbcb 100644 Binary files a/lib/FileUpload_Libx64d.lib and b/lib/FileUpload_Libx64d.lib differ diff --git a/server/2015Remote/2015Remote.cpp b/server/2015Remote/2015Remote.cpp index 5ee1bdc..a66728d 100644 --- a/server/2015Remote/2015Remote.cpp +++ b/server/2015Remote/2015Remote.cpp @@ -134,21 +134,21 @@ static BOOL HandleServiceCommandLine() // -service: 作为服务运行 if (cmdLine.Find(_T("-service")) != -1) { int r = ServerService_Run(); - Mprintf("[HandleServiceCommandLine] ServerService_Run %s", r ? "failed" : "succeed"); + Mprintf("[HandleServiceCommandLine] ServerService_Run %s\n", r ? "failed" : "succeed"); return TRUE; } // -install: 安装服务 if (cmdLine.Find(_T("-install")) != -1) { BOOL r = ServerService_Install(); - Mprintf("[HandleServiceCommandLine] ServerService_Install %s", !r ? "failed" : "succeed"); + Mprintf("[HandleServiceCommandLine] ServerService_Install %s\n", !r ? "failed" : "succeed"); return TRUE; } // -uninstall: 卸载服务 if (cmdLine.Find(_T("-uninstall")) != -1) { BOOL r = ServerService_Uninstall(); - Mprintf("[HandleServiceCommandLine] ServerService_Uninstall %s", !r ? "failed" : "succeed"); + Mprintf("[HandleServiceCommandLine] ServerService_Uninstall %s\n", !r ? "failed" : "succeed"); return TRUE; } @@ -156,7 +156,7 @@ static BOOL HandleServiceCommandLine() // 此模式下正常运行GUI,但使用不同的互斥量名称避免冲突 if (cmdLine.Find(_T("-agent")) != -1) { // 继续正常启动GUI,但标记为代理模式 - Mprintf("[HandleServiceCommandLine] Run service agent: '%s'", cmdLine.GetString()); + Mprintf("[HandleServiceCommandLine] Run service agent: '%s'\n", cmdLine.GetString()); return FALSE; } @@ -165,7 +165,7 @@ static BOOL HandleServiceCommandLine() BOOL running = FALSE; char servicePath[MAX_PATH] = { 0 }; BOOL r = ServerService_CheckStatus(®istered, &running, servicePath, MAX_PATH); - Mprintf("[HandleServiceCommandLine] ServerService_CheckStatus %s", !r ? "failed" : "succeed"); + Mprintf("[HandleServiceCommandLine] ServerService_CheckStatus %s\n", !r ? "failed" : "succeed"); char curPath[MAX_PATH]; GetModuleFileNameA(NULL, curPath, MAX_PATH); @@ -242,13 +242,13 @@ BOOL CMy2015RemoteApp::InitInstance() char curFile[MAX_PATH] = { 0 }; GetModuleFileNameA(NULL, curFile, MAX_PATH); if (!IsRunningAsAdmin() && LaunchAsAdmin(curFile, "runas")) { - Mprintf("[InitInstance] 程序没有管理员权限,用户选择以管理员身份重新运行。"); + Mprintf("[InitInstance] 程序没有管理员权限,用户选择以管理员身份重新运行。\n"); return FALSE; } // 首先处理服务命令行参数 if (HandleServiceCommandLine()) { - Mprintf("[InitInstance] 服务命令已处理,退出。"); + Mprintf("[InitInstance] 服务命令已处理,退出。\n"); return FALSE; // 服务命令已处理,退出 } @@ -268,7 +268,7 @@ BOOL CMy2015RemoteApp::InitInstance() } #endif - Mprintf("[InitInstance] 主控程序启动运行。"); + Mprintf("[InitInstance] 主控程序启动运行。\n"); SetUnhandledExceptionFilter(&whenbuged); // 创建并显示启动画面 @@ -349,10 +349,11 @@ int CMy2015RemoteApp::ExitInstance() // 只有在代理模式退出时才停止服务 if (IsAgentMode()) { ServerService_Stop(); - Mprintf("[InitInstance] 主控程序为代理模式,停止服务。"); + Mprintf("[InitInstance] 主控程序为代理模式,停止服务。\n"); } - Mprintf("[InitInstance] 主控程序退出运行。"); + Mprintf("[InitInstance] 主控程序退出运行。\n"); + Sleep(1000); return CWinApp::ExitInstance(); } diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 819dbaa..e89e6ae 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -3809,53 +3809,56 @@ void CMy2015RemoteDlg::OnDestroy() CString GetClipboardText() { - if (!OpenClipboard(nullptr)) return _T(""); + if (!OpenClipboard(nullptr)) return _T(""); + CString strText; + + // 优先获取 Unicode 格式 + HANDLE hData = GetClipboardData(CF_UNICODETEXT); + if (hData) { + wchar_t* pszText = static_cast(GlobalLock(hData)); + if (pszText) { #ifdef UNICODE - HANDLE hData = GetClipboardData(CF_UNICODETEXT); + strText = pszText; #else - HANDLE hData = GetClipboardData(CF_TEXT); + // 将 Unicode 转换为多字节(使用系统默认代码页) + int len = WideCharToMultiByte(CP_ACP, 0, pszText, -1, nullptr, 0, nullptr, nullptr); + if (len > 0) { + char* pBuf = strText.GetBuffer(len); + WideCharToMultiByte(CP_ACP, 0, pszText, -1, pBuf, len, nullptr, nullptr); + strText.ReleaseBuffer(); + } #endif + } + GlobalUnlock(hData); + } - if (!hData) { - CloseClipboard(); - return _T(""); - } - -#ifdef UNICODE - wchar_t* pszText = static_cast(GlobalLock(hData)); -#else - char* pszText = static_cast(GlobalLock(hData)); -#endif - - CString strText = pszText ? pszText : _T(""); - GlobalUnlock(hData); - CloseClipboard(); - return strText; + CloseClipboard(); + return strText; } -void SetClipboardText(const CString& text) +void SetClipboardText(const char* utf8Text) { - if (!OpenClipboard(nullptr)) return; - EmptyClipboard(); + if (!OpenClipboard(nullptr)) return; + EmptyClipboard(); -#ifdef UNICODE - HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, (text.GetLength() + 1) * sizeof(wchar_t)); - wchar_t* p = static_cast(GlobalLock(hGlob)); - if (p) wcscpy_s(p, text.GetLength() + 1, text); -#else - HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, (text.GetLength() + 1) * sizeof(char)); - char* p = static_cast(GlobalLock(hGlob)); - if (p) strcpy_s(p, text.GetLength() + 1, CT2A(text)); // CT2A 宏把 CString 转成 char* -#endif - - GlobalUnlock(hGlob); -#ifdef UNICODE - SetClipboardData(CF_UNICODETEXT, hGlob); -#else - SetClipboardData(CF_TEXT, hGlob); -#endif - CloseClipboard(); + // UTF-8 转 Unicode + int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8Text, -1, nullptr, 0); + if (wlen > 0) { + HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, wlen * sizeof(wchar_t)); + if (hGlob) { + wchar_t* p = static_cast(GlobalLock(hGlob)); + if (p) { + MultiByteToWideChar(CP_UTF8, 0, utf8Text, -1, p, wlen); + GlobalUnlock(hGlob); + SetClipboardData(CF_UNICODETEXT, hGlob); + } + else { + GlobalFree(hGlob); + } + } + } + CloseClipboard(); } CDialogBase* CMy2015RemoteDlg::GetRemoteWindow(HWND hWnd) @@ -3919,10 +3922,15 @@ LRESULT CALLBACK CMy2015RemoteDlg::LowLevelKeyboardProc(int nCode, WPARAM wParam } else { CString strText = GetClipboardText(); if (!strText.IsEmpty()) { + if (strText.GetLength() > 200*1024) { + Mprintf("【Ctrl+V】 从本地拷贝文本到远程失败, 文本太长: %d \n", strText.GetLength()); + break; + } BYTE* szBuffer = new BYTE[strText.GetLength() + 1]; szBuffer[0] = COMMAND_SCREEN_SET_CLIPBOARD; memcpy(szBuffer + 1, strText.GetString(), strText.GetLength()); - dlg->m_ContextObject->Send2Client(szBuffer, strText.GetLength() + 1); + if (dlg->m_ContextObject->Send2Client(szBuffer, strText.GetLength() + 1)) + Sleep(100); Mprintf("【Ctrl+V】 从本地拷贝文本到远程 \n"); SAFE_DELETE_ARRAY(szBuffer); } @@ -3945,7 +3953,8 @@ LRESULT CALLBACK CMy2015RemoteDlg::LowLevelKeyboardProc(int nCode, WPARAM wParam EmptyClipboard(); CloseClipboard(); } - g_2015RemoteDlg->m_pActiveSession->m_ContextObject->Send2Client(bToken, sizeof(bToken)); + if (g_2015RemoteDlg->m_pActiveSession->m_ContextObject->Send2Client(bToken, sizeof(bToken))) + Sleep(200); Mprintf("【Ctrl+V】 从远程拷贝到本地 \n"); } else { Mprintf("[Ctrl+V] 没有活动的远程桌面会话 \n"); diff --git a/server/2015Remote/IOCPServer.cpp b/server/2015Remote/IOCPServer.cpp index 6abf704..aea0e29 100644 --- a/server/2015Remote/IOCPServer.cpp +++ b/server/2015Remote/IOCPServer.cpp @@ -605,7 +605,7 @@ BOOL IOCPServer::OnClientPostSending(CONTEXT_OBJECT* ContextObject,ULONG ulCompl int iOk = WSASend(ContextObject->sClientSocket, &ContextObject->wsaOutBuffer,1, NULL, ulFlags,&OverlappedPlus->m_ol, NULL); if ( iOk == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING ) { - int a = GetLastError(); + int a = WSAGetLastError(); Mprintf("!!! OnClientPostSending 投递消息失败: %d\n", a); RemoveStaleContext(ContextObject); SAFE_DELETE(OverlappedPlus); diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 66569b8..5f36056 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -797,22 +797,36 @@ BOOL CScreenSpyDlg::SaveSnapshot(void) } -VOID CScreenSpyDlg::UpdateServerClipboard(char *szBuffer,ULONG ulLength) +VOID CScreenSpyDlg::UpdateServerClipboard(char* szBuffer, ULONG ulLength) { - if (!::OpenClipboard(NULL)) - return; + if (!::OpenClipboard(NULL)) + return; - ::EmptyClipboard(); - HGLOBAL hGlobal = GlobalAlloc(GPTR, ulLength); - if (hGlobal != NULL) { + ::EmptyClipboard(); - char* szClipboardVirtualAddress = (LPTSTR) GlobalLock(hGlobal); - memcpy(szClipboardVirtualAddress,szBuffer,ulLength); - GlobalUnlock(hGlobal); - if(NULL==SetClipboardData(CF_TEXT, hGlobal)) - GlobalFree(hGlobal); - } - CloseClipboard(); + // UTF-8 转 Unicode + int wlen = MultiByteToWideChar(CP_UTF8, 0, szBuffer, ulLength, nullptr, 0); + if (wlen > 0) { + // 分配 Unicode 缓冲区(+1 确保 null 结尾) + HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, (wlen + 1) * sizeof(wchar_t)); + if (hGlobal != NULL) { + wchar_t* pWideStr = (wchar_t*)GlobalLock(hGlobal); + if (pWideStr) { + MultiByteToWideChar(CP_UTF8, 0, szBuffer, ulLength, pWideStr, wlen); + pWideStr[wlen] = L'\0'; // 确保 null 结尾 + GlobalUnlock(hGlobal); + + if (SetClipboardData(CF_UNICODETEXT, hGlobal) == NULL) { + GlobalFree(hGlobal); + } + } + else { + GlobalFree(hGlobal); + } + } + } + + CloseClipboard(); } VOID CScreenSpyDlg::SendServerClipboard(void)