Windows 事件日誌採用「事件源 + 訊息 DLL」架構。應用程式需先註冊事件源,指定訊息 DLL 路徑與支援的事件類型,寫入時由系統載入 DLL 格式化訊息,讀取時同樣需 DLL 解析。
HKEY hk; ULONG disposition, allowed;
char szName[256];
strcpy(szName, "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\");
strcat(szName, "MyApp"); // 事件源名稱
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szName, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hk, &disposition)) return;
strcpy(szName, "%SystemRoot%\\System32\\MYDLL.DLL"); // 訊息 DLL 路徑
RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE)szName, strlen(szName)+1);
allowed = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE)&allowed, sizeof(DWORD));
RegCloseKey(hk);
建立 .mc 訊息定義檔:
LanguageNames=(Chinese=2052:MSG0052)
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR)
MessageId=1000 Severity=Success SymbolicName=MYAPP_STATUS_OK
Language=Chinese
應用程式運行正常.
.
MessageId=1001 Severity=Error SymbolicName=MYAPP_ERROR_GENERIC
Language=Chinese
發生錯誤,原因:%1
.
編譯流程:mc.exe → 產生 .h、.rc、.bin → 建立 Win32 DLL 專案加入資源編譯 → 輸出 MYDLL.DLL 放入 System32 目錄。
// C/C++ 版本
BOOL WriteEventLog(DWORD dwEventID, char* pszMsg, WORD wType)
{
HANDLE hEventLog = RegisterEventSource(NULL, "MyApp");
if (!hEventLog) return FALSE;
LPCTSTR strings[] = { pszMsg };
BOOL bResult = ReportEvent(hEventLog, wType, 0, dwEventID, NULL, 1, 0, strings, NULL);
DeregisterEventSource(hEventLog);
return bResult;
}
// Visual Basic 版本 (Declare 差異注意)
Private Declare Function ReportEvent Lib "advapi32" Alias "ReportEventA" (...)
void CEventDlg::OnReadLog()
{
HANDLE hLog = OpenEventLog(NULL, "Application");
EVENTLOGRECORD* pRecord = (EVENTLOGRECORD*)buffer;
DWORD dwRead, dwNeeded;
while (ReadEventLog(hLog, EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,
0, pRecord, sizeof(buffer), &dwRead, &dwNeeded))
{
// 解析 EVENTLOGRECORD 結構
// EventID, EventType, TimeWritten, SourceName, ComputerName, Strings...
// Strings 緊接在 EVENTLOGRECORD 結構之後,需手動指標運算遍歷
}
CloseEventLog(hLog);
}
%SystemRoot% 展開環境變數,且 DLL 需放在系統目錄2052 (0x0804),MC 檔需明確宣告%1~%9 對應 ReportEvent 的字串陣列參數
圖一 事件檢視器顯示自訂事件效果
事件日誌機制雖繁瑣但功能強大,適合企業級應用記錄稽核追蹤。讀取端解析 EVENTLOGRECORD 結構較複雜,歡迎分享更簡潔的封裝方法。完整範例含 MC 檔、DLL 專案、讀寫測試程式。