BOOL ReportEvent( _In_ HANDLE hEventLog, _In_ WORD wType, _In_ WORD wCategory, _In_ DWORD dwEventID, _In_ PSID lpUserSid, _In_ WORD wNumStrings, _In_ DWORD dwDataSize, _In_ LPCTSTR *lpStrings, _In_ LPVOID lpRawData );
最近要使用windows服务,需要记录一下系统日志,来学习一下,winodws 中的报告事件。
上面是ReportEvent的函数声明,具体参数意义见:http://msdn.microsoft.com/ZH-CN/library/windows/desktop/aa363679%28v=vs.85%29.aspx
以下是对http://msdn.microsoft.com/ZH-CN/library/windows/desktop/aa363680%28v=vs.85%29.aspx
中的实践
----分隔线----
为了报告事件,你必须先在消息文本中定义事件。更多写一个消息文本文件见消息文本文件。
下面给出了例子中所用的消息文件文件。
(注意复制时,最后一个"."后面还有一个行,如果没有这一行,会出现“invalid character (0x2e)”错误)
; // MyEventProvider.mc ; // This is the header section. SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS Informational=0x1:STATUS_SEVERITY_INFORMATIONAL Warning=0x2:STATUS_SEVERITY_WARNING Error=0x3:STATUS_SEVERITY_ERROR ) FacilityNames=(System=0x0:FACILITY_SYSTEM Runtime=0x2:FACILITY_RUNTIME Stubs=0x3:FACILITY_STUBS Io=0x4:FACILITY_IO_ERROR_CODE ) LanguageNames=(English=0x409:MSG00409) ; // The following are the categories of events. MessageIdTypedef=WORD MessageId=0x1 SymbolicName=NETWORK_CATEGORY Language=English Network Events . MessageId=0x2 SymbolicName=DATABASE_CATEGORY Language=English Database Events . MessageId=0x3 SymbolicName=UI_CATEGORY Language=English UI Events . ; // The following are the message definitions. MessageIdTypedef=DWORD MessageId=0x100 Severity=Error Facility=Runtime SymbolicName=MSG_INVALID_COMMAND Language=English The command is not valid. . MessageId=0x101 Severity=Error Facility=System SymbolicName=MSG_BAD_FILE_CONTENTS Language=English File %1 contains content that is not valid. . MessageId=0x102 Severity=Warning Facility=System SymbolicName=MSG_RETRIES Language=English There have been %1 retries with %2 success! Disconnect from the server and try again later. . MessageId=0x103 Severity=Informational Facility=System SymbolicName=MSG_COMPUTE_CONVERSION Language=English %1 %%4096 = %2 %%4097. . ; // The following are the parameter strings */ MessageId=0x1000 Severity=Success Facility=System SymbolicName=QUARTS_UNITS Language=English quarts%0 . MessageId=0x1001 Severity=Success Facility=System SymbolicName=GALLONS_UNITS Language=English gallons%0 .
为了编译这个消息文本文件,使用下面命令:
mc -U provider.mc
rc provider.rc
link -dll -noentry provider.res
// MyEventProvider.mc // This is the header section. // The following are categories of events. // // Values are 32 bit values laid out as follows: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---+-+-+-----------------------+-------------------------------+ // |Sev|C|R| Facility | Code | // +---+-+-+-----------------------+-------------------------------+ // // where // // Sev - is the severity code // // 00 - Success // 01 - Informational // 10 - Warning // 11 - Error // // C - is the Customer code flag // // R - is a reserved bit // // Facility - is the facility code // // Code - is the facility's status code // // // Define the facility codes // #define FACILITY_SYSTEM 0x0 #define FACILITY_STUBS 0x3 #define FACILITY_RUNTIME 0x2 #define FACILITY_IO_ERROR_CODE 0x4 // // Define the severity codes // #define STATUS_SEVERITY_WARNING 0x2 #define STATUS_SEVERITY_SUCCESS 0x0 #define STATUS_SEVERITY_INFORMATIONAL 0x1 #define STATUS_SEVERITY_ERROR 0x3 // // MessageId: NETWORK_CATEGORY // // MessageText: // // Network Events // #define NETWORK_CATEGORY ((WORD)0x00000001L) // // MessageId: DATABASE_CATEGORY // // MessageText: // // Database Events // #define DATABASE_CATEGORY ((WORD)0x00000002L) // // MessageId: UI_CATEGORY // // MessageText: // // UI Events // #define UI_CATEGORY ((WORD)0x00000003L) // The following are message definitions. // // MessageId: MSG_INVALID_COMMAND // // MessageText: // // The command is not valid. // #define MSG_INVALID_COMMAND ((DWORD)0xC0020100L) // // MessageId: MSG_BAD_FILE_CONTENTS // // MessageText: // // File %1 contains content that is not valid. // #define MSG_BAD_FILE_CONTENTS ((DWORD)0xC0000101L) // // MessageId: MSG_RETRIES // // MessageText: // // There have been %1 retries with %2 success! Disconnect from // the server and try again later. // #define MSG_RETRIES ((DWORD)0x80000102L) // // MessageId: MSG_COMPUTE_CONVERSION // // MessageText: // // %1 %%4096 = %2 %%4097. // #define MSG_COMPUTE_CONVERSION ((DWORD)0x40000103L) // The following are the parameter strings */ // // MessageId: QUARTS_UNITS // // MessageText: // // quarts%0 // #define QUARTS_UNITS ((DWORD)0x00001000L) // // MessageId: GALLONS_UNITS // // MessageText: // // gallons%0 // #define GALLONS_UNITS ((DWORD)0x00001001L)
#ifndef UNICODE #define UNICODE #endif #include <windows.h> #include <stdio.h> #include "provider.h" #pragma comment(lib, "advapi32.lib") #define PROVIDER_NAME L"MyEventProvider" // Hardcoded insert string for the event messages. CONST LPWSTR pBadCommand = L"The command that was not valid"; CONST LPWSTR pFilename = L"c:\\folder\\file.ext"; CONST LPWSTR pNumberOfRetries = L"3"; CONST LPWSTR pSuccessfulRetries = L"0"; CONST LPWSTR pQuarts = L"8"; CONST LPWSTR pGallons = L"2"; void wmain(void) { HANDLE hEventLog = NULL; LPWSTR pInsertStrings[2] = {NULL, NULL}; DWORD dwEventDataSize = 0; // The source name (provider) must exist as a subkey of Application. hEventLog = RegisterEventSource(NULL, PROVIDER_NAME); if (NULL == hEventLog) { wprintf(L"RegisterEventSource failed with 0x%x.\n", GetLastError()); goto cleanup; } // This event includes user-defined data as part of the event. The event message // does not use insert strings. dwEventDataSize = ((DWORD)wcslen(pBadCommand) + 1) * sizeof(WCHAR); if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, UI_CATEGORY, MSG_INVALID_COMMAND, NULL, 0, dwEventDataSize, NULL, pBadCommand)) { wprintf(L"ReportEvent failed with 0x%x for event 0x%x.\n", GetLastError(), MSG_INVALID_COMMAND); goto cleanup; } // This event uses insert strings. pInsertStrings[0] = pFilename; if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, DATABASE_CATEGORY, MSG_BAD_FILE_CONTENTS, NULL, 1, 0, (LPCWSTR*)pInsertStrings, NULL)) { wprintf(L"ReportEvent failed with 0x%x for event 0x%x.\n", GetLastError(), MSG_BAD_FILE_CONTENTS); goto cleanup; } // This event uses insert strings. pInsertStrings[0] = pNumberOfRetries; pInsertStrings[1] = pSuccessfulRetries; if (!ReportEvent(hEventLog, EVENTLOG_WARNING_TYPE, NETWORK_CATEGORY, MSG_RETRIES, NULL, 2, 0, (LPCWSTR*)pInsertStrings, NULL)) { wprintf(L"ReportEvent failed with 0x%x for event 0x%x.\n", GetLastError(), MSG_RETRIES); goto cleanup; } // This event uses insert strings. pInsertStrings[0] = pQuarts; pInsertStrings[1] = pGallons; if (!ReportEvent(hEventLog, EVENTLOG_INFORMATION_TYPE, UI_CATEGORY, MSG_COMPUTE_CONVERSION, NULL, 2, 0, (LPCWSTR*)pInsertStrings, NULL)) { wprintf(L"ReportEvent failed with 0x%x for event 0x%x.\n", GetLastError(), MSG_COMPUTE_CONVERSION); goto cleanup; } wprintf(L"All events successfully reported.\n"); cleanup: if (hEventLog) DeregisterEventSource(hEventLog); }
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application下表显示了如何写MyEventProvider中的项
Value name | Type | Value data |
---|---|---|
CategoryCount | REG_DWORD | 0x00000003 |
CategoryMessageFile | REG_SZ | path\provider.dll |
EventMessageFile | REG_SZ | path\provider.dll |
ParameterMessageFile | REG_SZ | path\provider.dll |
TypesSupported | REG_DWORD | 0x00000007 |
可以把下面的存为MyeventProvider.reg,然后运行下就注册好了。
前提是把
D:\\EventReport换成自己的路径
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application\MyEventProvider] "CategoryCount"=dword:00000003 "CategoryMessageFile"="D:\\EventReport\\provider.dll" "EventMessageFile"="D:\\EventReport\\provider.dll" "ParameterMessageFile"="D:\\EventReport\\provider.dll" "TypesSupported"=dword:00000007
注册好之后运行程序
在事件查看器中,可以看到下图:
进一步用法,还要摸索中,来日再来补充。