事件记录API不写入系统日志

时间:2014-03-11 07:27:29

标签: c++ windows event-log

我正在使用旧的Event Logging 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。我是源和生成事件的注册表。

但是,即使我指定了System,我也可以看到正在创建的密钥,但所有这些事件只会转到应用程序日志。

我做错了什么?

此外,我假设mc文件中的FacilityNames部分引用要写入的日志(没有关于此的良好文档)。这是对的吗?

1 个答案:

答案 0 :(得分:0)

如果您尝试将消息记录到无法找到的事件源,则事件将转到应用程序日志。仅仅创建一个事件源的子键可能还不够。在Vista之前,您需要在parent log's key中添加/更新类型为Sources的{​​{1}}值,以指定可写入该日志的事件源。除非您仅定位Vista及更高版本,否则您不会采取这一步骤。

Windows应该监视日志的子键并为您维护REG_MULTI_SZ,但根据我的经验并不总是正常工作。在Vista之前,如果您没有自己使Sources保持最新状态,则事件日志服务不会及时检测到动态添加/删除的事件源(如果有的话)。

不,Sources与您可以写入的日志无关。它仅定义了在指定消息ID的FacilityNames位时可以使用的符号名称,而不是指定硬编码的数字。没什么。

唯一指示您撰写任何给定消息的日志是您在facility中指定的事件源。在注册写入源之前,必须确保源作为目标日志密钥的子项存在,并且还存在于Vista之前的日志RegisterEventSource()值中。