首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows 2000 事件日誌讀寫完整指南:從註冊事件源到 DLL 訊息編譯

     編輯:關於VC++

架構概覽

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);

二、編譯訊息 DLL (MC 編譯器)

建立 .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);
}

五、常見坑點與驗證

  • DLL 路徑:必須使用 %SystemRoot% 展開環境變數,且 DLL 需放在系統目錄
  • 語言 ID:中文環境對應 2052 (0x0804),MC 檔需明確宣告
  • 參數替換:%1~%9 對應 ReportEvent 的字串陣列參數
  • 缺少 DLL 現象:事件檢視器會顯示「找不到描述」,但仍顯示原始參數字串

圖一 事件檢視器顯示自訂事件效果

六、總結

事件日誌機制雖繁瑣但功能強大,適合企業級應用記錄稽核追蹤。讀取端解析 EVENTLOGRECORD 結構較複雜,歡迎分享更簡潔的封裝方法。完整範例含 MC 檔、DLL 專案、讀寫測試程式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved