17

I found an example in C# how to add new Event to the Event Viewer. But, I need an example written in C++ (not .NET) that create new Event to the Event Viewer under the "Application" part.

Darren Burgess
  • 4,200
  • 6
  • 27
  • 43
Moti
  • 897
  • 4
  • 12
  • 21
  • Here is a simpler, straight forward solution to get basic event logging working: https://stackoverflow.com/questions/37035958/log-to-event-viewer-on-windows-with-c – infamed Apr 20 '21 at 00:05

2 Answers2

23

You can use these three functions from the WINAPI:

Here is a quick example of how to use these and to display messages correctly in the event log (error handling mostly ignored for brevity).

Create a resource containg message information from the following Event_log.mc file:

;#ifndef _EXAMPLE_EVENT_LOG_MESSAGE_FILE_H_
;#define _EXAMPLE_EVENT_LOG_MESSAGE_FILE_H_

MessageIdTypeDef=DWORD


SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
               Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
               Warning=0x2:STATUS_SEVERITY_WARNING
               Error=0x3:STATUS_SEVERITY_ERROR
               )

LanguageNames=(EnglishUS=0x401:MSG00401
               Dutch=0x113:MSG00113
               Neutral=0x0000:MSG00000
               )

MessageId=0x0   SymbolicName=MSG_INFO_1
Severity=Informational
Facility=Application
Language=Neutral
%1
.

MessageId=0x1   SymbolicName=MSG_WARNING_1
Severity=Warning
Facility=Application
Language=Neutral
%1
.

MessageId=0x2   SymbolicName=MSG_ERROR_1
Severity=Error
Facility=Application
Language=Neutral
%1
.

MessageId=0x3   SymbolicName=MSG_SUCCESS_1
Severity=Success
Facility=Application
Language=Neutral
%1
.


;#endif

To build the .mc file and .res resource file I executed the following:

mc.exe -A -b -c -h . -r resources Event_log.mc
rc.exe -foresources/Event_log.res resources/Event_log.rc

This will create a header file called Event_log.h in the current directory and a resources directory containing a file named Event_log.res which you must link in to your application binary.

Example main.cpp:

#include <windows.h>
#include "Event_log.h"

void install_event_log_source(const std::string& a_name)
{
    const std::string key_path("SYSTEM\\CurrentControlSet\\Services\\"
                               "EventLog\\Application\\" + a_name);

    HKEY key;

    DWORD last_error = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
                                      key_path.c_str(),
                                      0,
                                      0,
                                      REG_OPTION_NON_VOLATILE,
                                      KEY_SET_VALUE,
                                      0,
                                      &key,
                                      0);

    if (ERROR_SUCCESS == last_error)
    {
        BYTE exe_path[] = "C:\\path\\to\\your\\application.exe";
        DWORD last_error;
        const DWORD types_supported = EVENTLOG_ERROR_TYPE   |
                                      EVENTLOG_WARNING_TYPE |
                                      EVENTLOG_INFORMATION_TYPE;

        last_error = RegSetValueEx(key,
                                   "EventMessageFile",
                                   0,
                                   REG_SZ,
                                   exe_path,
                                   sizeof(exe_path));

        if (ERROR_SUCCESS == last_error)
        {
            last_error = RegSetValueEx(key,
                                       "TypesSupported",
                                       0,
                                       REG_DWORD,
                                       (LPBYTE) &types_supported,
                                       sizeof(types_supported));
        }

        if (ERROR_SUCCESS != last_error)
        {
            std::cerr << "Failed to install source values: "
                << last_error << "\n";
        }

        RegCloseKey(key);
    }
    else
    {
        std::cerr << "Failed to install source: " << last_error << "\n";
    }
}

void log_event_log_message(const std::string& a_msg,
                           const WORD         a_type,
                           const std::string& a_name)
{
    DWORD event_id;

    switch (a_type)
    {
        case EVENTLOG_ERROR_TYPE:
            event_id = MSG_ERROR_1;
            break;
        case EVENTLOG_WARNING_TYPE:
            event_id = MSG_WARNING_1;
            break;
        case EVENTLOG_INFORMATION_TYPE:
            event_id = MSG_INFO_1;
            break;
        default:
            std::cerr << "Unrecognised type: " << a_type << "\n";
            event_id = MSG_INFO_1;
            break;
    }

    HANDLE h_event_log = RegisterEventSource(0, a_name.c_str());

    if (0 == h_event_log)
    {
        std::cerr << "Failed open source '" << a_name << "': " <<
            GetLastError() << "\n";
    }
    else
    {
        LPCTSTR message = a_msg.c_str();

        if (FALSE == ReportEvent(h_event_log,
                                 a_type,
                                 0,
                                 event_id,
                                 0,
                                 1,
                                 0,
                                 &message,
                                 0))
        {
            std::cerr << "Failed to write message: " <<
                GetLastError() << "\n";
        }

        DeregisterEventSource(h_event_log);
    }
}

void uninstall_event_log_source(const std::string& a_name)
{
    const std::string key_path("SYSTEM\\CurrentControlSet\\Services\\"
                               "EventLog\\Application\\" + a_name);

    DWORD last_error = RegDeleteKey(HKEY_LOCAL_MACHINE,
                                    key_path.c_str());

    if (ERROR_SUCCESS != last_error)
    {
        std::cerr << "Failed to uninstall source: " << last_error << "\n";
    }
}

int main(int a_argc, char** a_argv)
{
    const std::string event_log_source_name("my-test-event-log-source");

    install_event_log_source(event_log_source_name);

    log_event_log_message("hello, information",
                          EVENTLOG_INFORMATION_TYPE,
                          event_log_source_name);

    log_event_log_message("hello, error",
                          EVENTLOG_ERROR_TYPE,
                          event_log_source_name);

    log_event_log_message("hello, warning",
                          EVENTLOG_WARNING_TYPE,
                          event_log_source_name);

    // Uninstall when your application is being uninstalled.
    //uninstall_event_log_source(event_log_source_name);

    return 0;
}

Hope this helps but consider that this approach has been deprecated as stated by @Cody Gray.

hmjd
  • 120,187
  • 20
  • 207
  • 252
  • 3
    Note that that API has been deprecated as of Windows Vista. New applications should use the [Windows Event Log API](http://msdn.microsoft.com/en-us/library/windows/desktop/aa385780.aspx) to log events. – Cody Gray - on strike Dec 19 '11 at 09:28
  • @CodyGray, ta. Never knew that. The older API still works (as far as I can tell) though as I use it without problems on Vista and Windows 7. – hmjd Dec 19 '11 at 09:30
  • Hi, As I mentioned before, the description give a general description and I just can add something to the end, but no change the whole description in the "Event Viewer". I would appreciate if you can point on an example that can change the description when using the ReportEvent function – Moti Dec 19 '11 at 13:38
  • First I would like thanks your fully description. I'm trying to compile it using the mc.exe but got an error. Which mc.exe do you use?. (ERROR: MC: Invalid switch: A MC: Invalid switch: b Microsoft (R) Message Compiler Version 1.00.5239) The mc.ex is run from C:\Program Files\Microsoft Visual Studio\VC98\Bin\mc.exe) – Moti Dec 20 '11 at 05:13
  • Anyway, I exchange the code and the application is registered in the Registry system but still got the default description (The description for Event ID ( 0 ) in Source ( my-test-event-log-source ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description;) – Moti Dec 20 '11 at 06:52
  • For what should I need the RES file? is it needed to be added to the Registry? – Moti Dec 20 '11 at 07:03
  • You need the `.res` to be linked to your binary to avoid the "The description for event ID.." message in the event log. I have a different version of VC (9 & 10), looks like you have quite an old one, VC98 (which is VC6 I think) so the message compiler may take different arguments from the one I use. – hmjd Dec 20 '11 at 07:15
  • Hi,For what should I need the RES file? is it needed to be added to the Registry? – Moti Dec 20 '11 at 12:34
  • No, see my previous comment. It does not get added to the registry but linked into your application executable. – hmjd Dec 20 '11 at 12:49
  • Unfortantly, I didn't work with the .res file before. What do you mean "*.res file link in to your application binary" and how should I do it? Sould I need to add the .res file to my project and compile it? if yes, what the compiler do with it? how it know how to refer this .res file? Thank – Moti Dec 20 '11 at 17:06
  • Add `Event_log.res` to the linker arguments (as you would for `.obj` files). – hmjd Dec 20 '11 at 17:21
  • I go to "Project Properties -> Linker -> Input -> Add Module to Assembly" and add "D:\loggingDemo\Event_log.RES" to it, but still the description is not changed. Thanks – Moti Dec 21 '11 at 05:04
  • 1
    Try adding to list of `.obj` files. Also, you will need to restart Event Viewer. – hmjd Dec 21 '11 at 07:59
  • When I'm trying to add it to the "Force Symbil Reference" the link is failed "error LNK2001: unresolved external symbol D:\loggingDemo\Event_log.RES". I also tried to reset the Event Viewer and still got it. – Moti Dec 21 '11 at 08:33
  • What VC version are you using? – hmjd Dec 21 '11 at 10:48
  • I don't use IDE's Moti, I build from commandline so I cant help you navigate the VC2010 IDE. However, this is my linker command: `link.exe -NOLOGO -INCREMENTAL:NO -OUT:stackoverflow.exe C:\projects\play\stackoverflow\stackoverflow.obj resources/Event_log.res Kernel32.lib advapi32.lib psapi.lib user32.lib`. Also, use `C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\mc.exe` message compiler. – hmjd Dec 21 '11 at 11:23
  • Thank you very much for your help. It very helped me with the first question, I will try to see how it could be with the VS2010. – Moti Dec 21 '11 at 11:51
  • This is about 200 lines more than is needed for a simple example. I will continue my search. – Owl May 05 '17 at 13:28
  • Simpler solution: https://stackoverflow.com/questions/37035958/log-to-event-viewer-on-windows-with-c – infamed Apr 20 '21 at 00:05
9

You're looking for the documentation on the Windows Event Log API. You'll need to call the native Win32 API functions, rather than use the .NET Framework's wrappers, since you're writing in unmanaged C++.

If you're targeting operating systems prior to Windows Vista (XP, Server 2003, etc.), you'll need to use the older Event Logging API instead.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Hi, I used the link you attached to Microsoft and there is a good example. But, There is no option to change the Description and when I go to the "Event Viewer" and open the description, I found the follwoing lines: "The description for Event ID ( 259 ) in Source ( MyEventProvider ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event:" – Moti Dec 19 '11 at 13:04
  • Both links go to the same URL. – infamed Apr 20 '21 at 00:02