diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 4d90ba1..b3b7bbe 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -8779,22 +8779,21 @@ void CMy2015RemoteDlg::OnListClick(NMHDR* pNMHDR, LRESULT* pResult) CString startTime = ctx->GetClientData(ONLINELIST_STARTTIME); ctx->GetAdditionalData(res); // 客户端 RES_* 字符串编码取决于客户端能力位:UTF-8 客户端(Linux/macOS/新 Win) - // 发的是 UTF-8 字节,老客户端是 CP_ACP。这里统一规整到 CP_ACP,让下游 FormatL - // 与既有 ANSI 字符串拼接以及最终 CP_ACP→wide 的浮窗渲染都能正确识别。 - // 若服务端运行系统的 ANSI 代码页不能容纳客户端字符(如德语服务端遇到中文路径), - // 不可表示的字符会变 '?' —— 与项目其它路径的既有限制一致,不在本次修复范围。 + // 发的是 UTF-8 字节,老客户端是 GBK。这里统一规整到 GBK(936) —— 工程内部 ANSI + // 约定即 GBK(/execution-charset:.936 + setlocale(".936")),不随系统 ACP 变。 + // 下游 FormatL 拼接、以及最终 936→wide 的浮窗渲染都能据此正确识别中文。 UINT cp = GetClientEncoding(ctx); - if (cp != CP_ACP) { + if (cp != 936) { for (int i = 0; i < RES_MAX; i++) { if (res[i].IsEmpty()) continue; int wlen = MultiByteToWideChar(cp, 0, res[i].GetString(), -1, NULL, 0); if (wlen <= 1) continue; std::wstring wbuf(wlen - 1, L'\0'); MultiByteToWideChar(cp, 0, res[i].GetString(), -1, &wbuf[0], wlen); - int alen = WideCharToMultiByte(CP_ACP, 0, wbuf.c_str(), -1, NULL, 0, NULL, NULL); + int alen = WideCharToMultiByte(936, 0, wbuf.c_str(), -1, NULL, 0, NULL, NULL); if (alen <= 1) continue; CString out; - WideCharToMultiByte(CP_ACP, 0, wbuf.c_str(), -1, + WideCharToMultiByte(936, 0, wbuf.c_str(), -1, out.GetBufferSetLength(alen - 1), alen, NULL, NULL); out.ReleaseBuffer(alen - 1); res[i] = out; @@ -8849,13 +8848,14 @@ void CMy2015RemoteDlg::OnListClick(NMHDR* pNMHDR, LRESULT* pResult) } auto* tip = new CPreviewTipWnd(); - // 项目是 MBCS(CP_ACP),浮窗内部用宽字符渲染(避免跨语言系统乱码)。 - // 这里把 strText (CStringA) 按 CP_ACP 转 wide。 + // 浮窗内部用宽字符渲染。strText 里的中文(标签来自 GBK 源字面量,路径/用户名 + // 已在上方规整为 GBK)统一是 GBK(936),按 936 转 wide 而非系统 CP_ACP —— + // 否则非中文 ACP(德语/英语等)服务端会把中文解成乱码。 CStringW textW; { - int wlen = MultiByteToWideChar(CP_ACP, 0, strText.GetString(), -1, NULL, 0); + int wlen = MultiByteToWideChar(936, 0, strText.GetString(), -1, NULL, 0); if (wlen > 1) { - MultiByteToWideChar(CP_ACP, 0, strText.GetString(), -1, textW.GetBufferSetLength(wlen - 1), wlen); + MultiByteToWideChar(936, 0, strText.GetString(), -1, textW.GetBufferSetLength(wlen - 1), wlen); textW.ReleaseBuffer(wlen - 1); } } diff --git a/server/2015Remote/CClientListDlg.cpp b/server/2015Remote/CClientListDlg.cpp index a89d866..01a8f74 100644 --- a/server/2015Remote/CClientListDlg.cpp +++ b/server/2015Remote/CClientListDlg.cpp @@ -5,6 +5,7 @@ #include "afxdialogex.h" #include "CClientListDlg.h" #include "2015Remote.h" +#include // CClientListDlg 对话框 @@ -93,6 +94,27 @@ static CString GetFieldValue(const ClientValue& val, GroupField field) } } +// 客户端自报的程序路径是 UTF-8(见 client/LoginServer.cpp 的 RES_FILE_PATH), +// 这里用 LVM_SETITEMTEXTW 直接写宽字符串,绕开 ANSI→CP_ACP 回转, +// 即使服务端运行在非中文 ACP(如德语)上,中文路径也能正常显示(与窗口/进程管理同法)。 +static void SetProgramPathText(CListCtrl& list, int iItem, int iSubItem, const char* sz) +{ + std::wstring w; + if (sz && sz[0]) { + int wlen = MultiByteToWideChar(CP_UTF8, 0, sz, -1, NULL, 0); + if (wlen > 1) { + w.resize(wlen - 1); + MultiByteToWideChar(CP_UTF8, 0, sz, -1, &w[0], wlen); + } + } + LVITEMW lv = {}; + lv.mask = LVIF_TEXT; + lv.iItem = iItem; + lv.iSubItem = iSubItem; + lv.pszText = w.empty() ? const_cast(L"") : &w[0]; + ::SendMessageW(list.GetSafeHwnd(), LVM_SETITEMTEXTW, (WPARAM)iItem, (LPARAM)&lv); +} + // 比较两个客户端的指定列,返回 <0, 0, >0 static int CompareClientByColumn(const std::pair& a, const std::pair& b, @@ -299,7 +321,7 @@ void CClientListDlg::DisplayClients() m_ClientList.SetItemText(nItem, COL_OS, val.OsName); m_ClientList.SetItemText(nItem, COL_INSTALL_TIME, val.InstallTime); m_ClientList.SetItemText(nItem, COL_LAST_LOGIN, val.LastLoginTime); - m_ClientList.SetItemText(nItem, COL_PROGRAM_PATH, CString(val.ProgramPath)); + SetProgramPathText(m_ClientList, nItem, COL_PROGRAM_PATH, val.ProgramPath); m_ClientList.SetItemText(nItem, COL_LEVEL, strLevel); m_ClientList.SetItemText(nItem, COL_AUTH, strAuth); m_ClientList.SetItemData(nItem, (DWORD_PTR)key); @@ -351,7 +373,7 @@ void CClientListDlg::DisplayClients() m_ClientList.SetItemText(nItem, COL_OS, val.OsName); m_ClientList.SetItemText(nItem, COL_INSTALL_TIME, val.InstallTime); m_ClientList.SetItemText(nItem, COL_LAST_LOGIN, val.LastLoginTime); - m_ClientList.SetItemText(nItem, COL_PROGRAM_PATH, CString(val.ProgramPath)); + SetProgramPathText(m_ClientList, nItem, COL_PROGRAM_PATH, val.ProgramPath); m_ClientList.SetItemText(nItem, COL_LEVEL, strLevel); m_ClientList.SetItemText(nItem, COL_AUTH, strAuth); m_ClientList.SetItemData(nItem, (DWORD_PTR)key);