Я пользуюсь старым API регистрации событий записывать события в журналы событий, используя C ++.
Я могу записывать в журнал приложений, но не могу записать в системный журнал (я написал код на основе нескольких учебных пособий, которые я нашел в Интернете).
Вот мой MessageDef.mc
файл:
MessageIdTypeDef=DWORD
SeverityNames=(
Success=0x0:STATUS_SUCCESS
Informational=0x1:STATUS_INFORMATIONAL
Warning=0x2:STATUS_WARNING
Error=0x3:STATUS_ERROR
)
FacilityNames=(
System=0x0FF:FACILITY_SYSTEM
Application=0xFFF:FACILITY_APPLICATION
)
LanguageNames=(
EnglishUS=0x401:LAN_ENGLISHUS
Neutral=0x0:LAN_NEUTRAL
)
MessageId=0x0 SymbolicName=MSG_APPLOG
Severity=Informational
Facility=Application
Language=EnglishUS
%1
.
MessageId=0x1 SymbolicName=MSG_SYSLOG
Severity=Informational
Facility=System
Language=EnglishUS
%1
.
Вот файл, содержащий код, который устанавливает, регистрирует источник события и генерирует событие:
#include "CommonTasks.h"#include "EventGen.h"
int InstallEventLogSource(char *strExeName, char *strLogName)
{
std::string sLogName(strLogName), sExeName(strExeName);
std::string sLogKeyPathString = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + sLogName + "\\" + sExeName;
HKEY hKey;
DWORD status = RegCreateKeyEx(HKEY_LOCAL_MACHINE, sLogKeyPathString.c_str(), 0, 0, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, 0, &hKey, 0);
if(status == ERROR_SUCCESS)
{
char strFullExeName[MAX_EXE_NAME];
GetModuleFileName(NULL, strFullExeName, MAX_EXE_NAME);
BYTE bptrFullExeName[strlen(strFullExeName) + 1];
strcpy((char *)bptrFullExeName, strFullExeName);
status = RegSetValueEx(hKey, "EventMessageFile", 0, REG_SZ, bptrFullExeName, sizeof(bptrFullExeName));
if(status == ERROR_SUCCESS)
{
DWORD dwSeveritySupported = EVENTLOG_INFORMATION_TYPE;
status = RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE)&dwSeveritySupported, sizeof(dwSeveritySupported));
}
}
RegCloseKey(hKey);
}
int UninstallEventLogSource(char *strAppName, char *strLogName)
{
std::string sLogName(strLogName), sAppName(strAppName);
std::string sLogKeyPathString = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + sLogName + "\\" + sAppName;
DWORD status = RegDeleteKey(HKEY_LOCAL_MACHINE, sLogKeyPathString.c_str());
}
int WriteEventToLog(char *strMessage, char *strLogName, char *strLogSourceName)
{
DWORD dwEventId;
std::string sLogName(strLogName);
if(sLogName == "Application")
dwEventId = MSG_APPLOG;
else if(sLogName == "System")
dwEventId = MSG_SYSLOG;
HANDLE hEventLog = RegisterEventSource(0, strLogSourceName);
if(hEventLog)
{
ReportEvent(hEventLog, EVENTLOG_INFORMATION_TYPE, 0, dwEventId, 0, 1, 0,(const char **)&strMessage, 0);
}
DeregisterEventSource(hEventLog);
}
void GenerateEvents(int iEvtCount, char *strLogName)
{
char *strExeName = NULL;
GetExeName(&strExeName);
InstallEventLogSource(strExeName, strLogName);
WriteEventToLog("1", strLogName, strExeName);
UninstallEventLogSource(strExeName, strLogName);
}
Я создаю ключ с exe-именем моего приложения в необходимом журнале (передаваемом из другого вызывающего метода в другом файле), который может быть Application или System. Я регистрирую этот источник и генерирую событие.
Тем не менее, даже если я укажу «Система», я вижу, что ключ создается, но все эти события попадают только в журнал приложений.
Что я делаю неправильно ?
Также я иду с предположением, что FacilityNames
часть в файле mc ссылается на журнал для записи (нет хорошей документации по этому поводу). Это верно ?
События попадают в журнал приложений, если вы пытаетесь записать сообщение в источник событий, который не может быть найден. Простого создания подраздела источника событий может быть недостаточно. До Vista вам нужно добавить / обновить Sources
значение типа REG_MULTI_SZ
в ключ родительского журнала указать источники событий, которые могут записывать в этот журнал. Вы не делаете этот шаг, если только вы не ориентируетесь только на Vista и более поздние версии.
Предполагается, что Windows контролирует подключи журнала и поддерживает Sources
для вас, но по моему опыту, это не всегда работает правильно. До Vista, если вы не сохраните Sources
Вы можете быть в курсе, что служба журналов событий не обнаруживает динамически добавляемые / удаляемые источники событий своевременно, если это вообще происходит.
И нет, FacilityNames
не имеет никакого отношения к тем журналам, в которые вы можете писать. Он просто определяет символические имена, которые вы можете использовать при указании facility
биты ваших идентификаторов сообщений, а не указывать жестко закодированные номера. Ничего более.
только вещь, которая определяет, в какой журнал вы пишете какое-либо сообщение, является источником события, который вы указали в RegisterEventSource()
, Прежде чем вы сможете зарегистрировать источник для записи, вы должны убедиться, что источник существует как подраздел ключа целевого журнала, а также существует в журнале. Sources
значение до Vista.
Других решений пока нет …