| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- // =============================================================================
- // 诊断日志唯一出口的实现。说明见 Utils/UIDiag.h。
- //
- // 为什么是独立 .cpp(而不是 header-only + inline):
- // 如果写成头文件里的 inline 函数,每个包含它的 .cpp 都会有一份 static 局部
- // 变量副本(s_buf / path 缓存),日志行为虽然仍正确,但每次都重新
- // GetModuleFileName + 打开/关闭文件,且在 DLL 边界上语义容易含混。
- // 放 .cpp 里只编译一份 —— 这也是"全库只有本 .cpp 真正落盘"的实现基础。
- // =============================================================================
- #include "StdAfx.h"
- #include "UIDiag.h"
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- namespace DuiLibDiag
- {
- // ★ 全库唯一的日志开关:需要关闭诊断时改这里(返回 false)。
- inline bool Enabled()
- {
- return true;
- }
- // 极简 TCHAR* → UTF-8 char* 转换(仅用于日志路径;非线程安全,够用即可)
- static const char* Narrow(LPCTSTR s)
- {
- static char s_buf[MAX_PATH * 3] = { 0 };
- #ifdef _UNICODE
- s_buf[0] = '\0';
- if (s != NULL)
- ::WideCharToMultiByte(CP_UTF8, 0, s, -1, s_buf, (int)sizeof(s_buf) - 1, NULL, NULL);
- return s_buf;
- #else
- return s;
- #endif
- }
- void Log(LPCTSTR fmt, ...)
- {
- if (!Enabled()) return;
- TCHAR path[MAX_PATH] = { 0 };
- ::GetModuleFileName(NULL, path, MAX_PATH);
- TCHAR* p = _tcsrchr(path, _T('\\'));
- if (p != NULL) *(p + 1) = _T('\0');
- _tcscat_s(path, MAX_PATH, _T("touch_trace.log"));
- TCHAR msg[1024] = { 0 };
- va_list ap;
- va_start(ap, fmt);
- _vsntprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
- va_end(ap);
- char utf8[2048] = { 0 };
- #ifdef _UNICODE
- if (::WideCharToMultiByte(CP_UTF8, 0, msg, -1, utf8, (int)sizeof(utf8) - 1, NULL, NULL) <= 0)
- return;
- #else
- _tcscpy_s(utf8, _countof(utf8), msg);
- #endif
- FILE* f = NULL;
- // 保护:单个日志超过 32MB 就不再追加,避免在收银机上长期运行把日志写到失控。
- // (全量 INPUT-TRACE 很啰嗦,阈值从 4MB 放宽到 32MB,否则一轮诊断还没跑完就静默停写了。)
- // 注意:GetFileAttributesEx 是 TCHAR 宏(Unicode 工程下展开为 ...ExW),
- // 必须传 TCHAR 的 path,不能传 Narrow(path) 得到的 UTF-8 char*(否则 C2664)。
- WIN32_FILE_ATTRIBUTE_DATA fad = { 0 };
- if (::GetFileAttributesEx(path, GetFileExInfoStandard, &fad)
- && fad.nFileSizeHigh == 0 && fad.nFileSizeLow >= (32u * 1024u * 1024u))
- return;
- // fopen_s 只吃 char*(窄字符路径),这里才需要 UTF-8 的 Narrow(path)
- if (fopen_s(&f, Narrow(path), "a") == 0 && f != NULL)
- {
- fprintf(f, "[%8u][T%5u] %s\n", (unsigned)::GetTickCount(), (unsigned)::GetCurrentThreadId(), utf8);
- // 立刻冲盘:程序被强杀 / 挂死 / 断电时,日志尾部(往往正是关键现场)不能丢。
- fflush(f);
- fclose(f);
- }
- }
- void LogButtonActivate(LPCTSTR name, bool captureState, unsigned buttonState, bool pushed)
- {
- // 位域含义(取自 UIManager.h 的 #define,勿凭记忆写):
- // UISTATE_DISABLED=0x04 / UISTATE_HOT=0x08
- // UISTATE_PUSHED=0x10 / UISTATE_CAPTURED=0x40
- Log(_T("BUTTON-ACTIVATE name=%s mgrCaptured=%d state=0x%04X pushed=%d hot=%d captured=%d disabled=%d"),
- name != NULL ? name : _T("null"),
- (int)(captureState ? 1 : 0),
- buttonState,
- (int)(pushed ? 1 : 0),
- (int)((buttonState & 0x0008u) ? 1 : 0),
- (int)((buttonState & 0x0040u) ? 1 : 0),
- (int)((buttonState & 0x0004u) ? 1 : 0));
- }
- }
|