Managed C++: Working with Windows Event Logs

My previous article illustrated how easy it is to access and modify the Windows Registry using the .NET Framework. Continuing with the theme of accessing Windows subsystems, this week's article shows how you can give your Managed C++ Windows applications a more polished, professional look by using the Windows Event Log to record warning, error, and informational messages.

Working with the Event Log involves quite a few tasks, so this series is divided among several parts. This article illustrates how to accomplish the following Event Log tasks:

  • Enumerate the logs on the local or any connected remote machine (for which the application has sufficient rights)
  • Instantiate an EventLog object for a specific local or remote log
  • Create your own custom event logs that are specific to your application
  • Delete event logs

Future articles will cover how to read and write to the event log (using versions 1.1 and 2.0 of the .NET Framework) and how to monitor the event log for changes.

Important notes before continuing:
  • Because the Event Log is a Windows service, this article pertains only to Windows NT, 2000, XP, 2003, and Longhorn.
  • I could write quite a bit about the Event Log in terms of what it is and why I believe it's a much better means of recording application messages than using log files. However, I won't get too much into philosophical issues and instead focus on code. If you are interested in this information, drop me an e-mail and I'll post an excerpt from my book Extending MFC Applications with the .NET Framework where I cover these issues.

A (Very Quick) Briefing on the Event Log and Viewer

The Windows Event Log is a service that starts when Windows loads. It is used as a central repository for applications to record messages related to the success or failure of their respective tasks. There are three standard, system-supplied logs: Application, Security, and System. Windows also supplies an application for viewing and modifying the logs. You can access this application (called the Event Viewer) via the Windows menu system or by typing eventvwr at the Run prompt. The Event Viewer allows you to search, filter, create views on, back up, and restore event log messages.

Applications (event sources) record messages (events) into a specified log. The exact log an event source uses typically depends on the type of application recording the event. For example, the System event log is used by services and kernel mode programs such as device drivers. The Security event log is used by applications that need to record log-on attempts, suspicious port scans, and other security events. (Note that the Security event log restricts normal-mode applications to read-only access for obvious reasons.) Finally, the Application event log is used by the majority of user-mode Windows applications. In addition to these logs, you also can define your own logs (called custom event logs), which this article also covers.

Instantiating EventLog Objects and Enumerating Event Logs

The main .NET class that you will work with when accessing the Event Log from a Managed C++ application is the Diagnostics::EventLog class. You can construct an EventLog object in the following two ways:

  • Calling one of the EventLog overloaded constructors where you specify such information as the log name, machine name, and the event source name
  • Calling the static EventLog::GetEventLogs method, which returns all logs for which the user has permissions on either the local machine or the specified remote machine

When specifying a log name, realize that log names are not case-sensitive. However, the .NET runtime will throw a System::IO::IOException exception if you specify a log name that is not found. Also note that the local machine can be designated via passing a period (".") as the machine name:

// Get local machine's Application log
EventLog* el = new EventLog(S"application");

// Get Application log from the "myserver"
EventLog* e2 = new EventLog(S"application", S"myserver");

// Get Application log from the local machine for the event source
// named "my application"
EventLog* e3 = new EventLog(S"application", S".", S"my application");

To retrieve an array of all of the logs, call the EventLog::GetEventLogs method, where you can pass a string value specifying the machine. Remember that passing a value of "." indicates the local machine, as does calling the parameterless version of this method:

EventLog* logs[] = EventLog::GetEventLogs();
for (int i = 0; i < logs->Count; i++)
  Console::WriteLine(S"{0}", logs[i]->LogDisplayName);

Managed C++: Working with Windows Event Logs

Creating Custom Event Logs

As mentioned earlier, you also have the ability to programmatically create your own custom event logs. (Figure 1 shows a screen shot of my Event Viewer where I've created a custom event log called "My Application Log".) You typically use event logs in situations where you wish to keep your application's events separate from other event sources.

[EventLog1.jpg]

Figure 1: You can use the Windows Event Viewer to work with both system-supplied as well as custom event logs.

What's the advantage to defining a custom event log for your application? The main reason is support. Because the Event Viewer allows a user to export a log's events, the user is able to export only the events related to your application rather than an entire log containing events from other event sources. (The Event Viewer's filter function affects only what can be viewed; all events are exported when saving a log, regardless of the user-applied filter.)

Custom event logs are associated with specific event sources in a one-to-one relationship and are created via the static EventLog::CreateEventSource method. Because creating a custom event log entails also verifying if the event log already exists and deleting the event source if it's associated with another event log (event sources can be associated only with a single log), I list here a generic method for doing everything you need to create a custom event log:

// Method assumes caller will catch exceptions
// thrown by EventLog class
void CreateCustomEventLog(String* eventSource, String* logName)
{
#pragma push_macro("new")
#undef new

  // Does the Log already exist?
  if (!EventLog::Exists(logName))
  {
    // Does the event source already exist?
    if (EventLog::SourceExists(eventSource))
    {
      // Delete the event source because it can
      // only be associated with one log
      EventLog::DeleteEventSource(eventSource);
    }
    // Create the event source and associate it
    // with the new custom log.
    EventLog::CreateEventSource(eventSource, logName);
  }
#pragma pop_macro("new")
}
Only the first eight (8) characters of a custom log are significant. Therefore, when programmatically creating custom logs, you need to ensure that the log names are unique within the first eight characters or a System::ArgumentException will be thrown.

By using the CreateCustomEventMethod method, you can create your custom event logs like this:

// Create a custom event log called "My Application Log" for the
// event source "My Application"
CreateCustomEventLog(S"My Application", S"My Application Log");

Deleting Event Logs

Logs are programmatically deleted via the static EventLog::Delete method, where you pass the name of the log (and optionally, the machine name). As you can delete the system-supplied logs, be cautious when you use this method:

// Delete my custom event log
EventLog::Delete(S"My Application Log");

Who Has Access to My Event Log?

Each application that is defined as an event source capable of recording events to an event log is listed in the Windows Registry. You can see this by viewing the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\<LogName> Registry (where LogName is either one of the system-supplied event logs (Application, System, or Security) or the name of a custom event log. Figure 2 is a screen capture where I've selected the custom event log "My Application Log".

[EventLog2.jpg]

Figure 2: All event logs and event log sources are stored in the Registry in the HKLM hive.

Note that the event log subkey has a value called Sources. This value is a space-delimited string defining every event source that can write to that particular log. In addition, you can expand the event log subkey to see that each event source is also defined in its own subkey (below the event log subkey), where values such as EventMessageFile and TypesSupported are stored.

Looking Forward

As I mentioned at the outset of this article, I've divided this topic among several articles that each focus on a logically ordered task dealing with the Event Log. This article dealt with the event log tasks: enumerating local and remote event logs, instantiating an EventLog object for a specific local or remote event log, creating a custom event log, and deleting an event log. Upcoming articles will explore how to programmatically record and read events from an event log (using both 1.1 and 2.0 .NET functionality) and code an event log monitoring application.



About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

Most Popular Programming Stories

More for Developers

RSS Feeds