不在每個按鈕處理器寫 log,而是**建立自訂窗口類繼承 `CButton`/`CWnd`,重寫 `WindowProc` 攔截 `WM_COMMAND` (BN_CLICKED) 統一記錄**。
// 超類化按鈕類
class CLogButton : public CButton {
virtual LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp) {
if (msg == WM_COMMAND && HIWORD(wp) == BN_CLICKED) {
LogButtonClick(GetDlgCtrlID(), GetWindowText());
}
return CButton::WindowProc(msg, wp, lp);
}
void LogButtonClick(UINT id, CString text) {
CStdioFile f; f.Open(_T("log.txt"), CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite|CFile::shareDenyNone);
f.SeekToEnd();
CString log; log.Format(_T("[%s] BTN_ID=%u TEXT=%s\r\n"), CTime::GetCurrentTime().Format(_T("%Y-%m-%d %H:%M:%S")), id, text);
f.WriteString(log); f.Close();
}
};
對話框資源中將按鈕類別名改為 `CLogButton` (或動態 `SubclassDlgItem`)。
void LogHostInfo() {
char host[256]; gethostname(host, 256);
hostent* he = gethostbyname(host);
CString ip = (he && he->h_addr_list[0]) ? inet_ntoa(*(in_addr*)he->h_addr_list[0]) : _T("Unknown");
CStdioFile f; f.Open(_T("info.txt"), CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite);
f.SeekToEnd();
f.WriteString(CTime::GetCurrentTime().Format(_T("[%Y-%m-%d %H:%M:%S] Host=%s IP=%s\r\n")), host, ip);
f.Close();
}
痕跡保留三件套:**超類化按鈕統一 Log 點擊**、**啟動記錄 Host/IP**、**低頻採樣滑鼠軌跡退出寫檔**。關鍵在於「統一攔截點避免重複代碼」與「控制採樣頻率防止 IO/空間爆炸」。