0
votes

I am using the old Event Logging API to write events to the event logs using C++.

I can write to the Application log, but I am not being able to write to the System log (I wrote code based on a few tutorials I found online).

Here is my MessageDef.mc file:

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
.

Here is the file containing code which installs, registers the event source and generates an event:

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

I am creating a key with my application's exe name under the required log (passed in from another calling method in another file) which can be Application or System. I the register that source and generate an event.

However, even if I specify System, I can see the key being created but all those events go to the Application log only.

What am I doing wrong ?

Also I am going with the assumption that the FacilityNames part in the mc file refers to the log to write to (there isn't good documentation about this). Is that correct ?

1

1 Answers

0
votes

Events go to the Application log if you try to log a message to an event source that cannot be found. Merely creating an event source's subkey may not be enough. Prior to Vista, you need to add/update a Sources value of type REG_MULTI_SZ in the parent log's key to specify the event sources that can write to that log. You are not doing that step, unless you are only targeting Vista and later.

Windows is supposed to monitor the log's subkeys and maintain the Sources for you, but in my experience that does not always work correctly. Prior to Vista, if you do not keep the Sources up-to-date yourself, the eventlog service does not detect dynamically added/removed event sources in a timely manner, if at all.

And no, the FacilityNames has nothing to do with which logs you can write to. It merely defines symbolic names you can use when specifying the facility bits of your message IDs, rather than specifying hard-coded numbers. Nothing more.

The only thing that dictates which log you write any given message to is the event source you specify in RegisterEventSource(). Before you can register a source for writing, you have to make sure the source exists as a subkey of the target log's key, and also exists in the log's Sources value prior to Vista.