- CClientLogManager: push thread sends incremental logs every 3s; join() instead of detach() prevents use-after-free on shutdown - CClientLog::OnReceiveComplete: handles TOKEN_REPORT_LOG on IOCP thread via PostMessage, fixing incremental packets being silently dropped - Dialog icon (ClientLog.ico) and menu bitmap (ClientLog.bmp) added; OnInitDialog loads icon; IDR_MENU_LIST_ONLINE "运行日志" item gets the bitmap Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
107 lines
2.8 KiB
C++
107 lines
2.8 KiB
C++
// 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<std::string*>(lParam);
|
||
if (pText) {
|
||
AppendLog(*pText);
|
||
delete pText;
|
||
}
|
||
return 0;
|
||
}
|