Write to Eventlog with Delphi

Prerequisites:
- XN Ressource Editor
http://www.wilsonc.demon.co.uk/delphi.htm

General:
The Windows Eventlog does not hold the full Text which is displayed, it just holds the Values in the Text. If you see an Entry like "Application XYZ exited with errorcode 5", the Entry in the Eventlog just holds the Type of Event and the 5 as the Data. The Text itself is "Application XYZ exited with errorcode %1" and is hold (most often) in a ressource DLL. This DLL holds as much records in the String Table as the Application has Categories and Event ID´s. We will create a Ressource DLL to old the Text.

1. Create the Ressource DLL
Download the "XN Ressource Editor" and create a new String Table Ressource.
Add as much Format Strings as you like and save this as e.g. DLLMessages.res.
The first ones will the the categories (2 in my Example) and the following are the Event Descriptions.

Lets assume you added two Categories
1. Database Connection Error
2. Server Connection Error
and four Events
3. Failed to connect to database Server %1
4. Failed to connect to database %1 on Server %2
5. Failed to connect to Server %1
6. Failed to connect to Server %1 HR: %2

Now add a new DLL to your Delphi Project Group called e.g. MyRessourceDLL. Now add the compiler directive {$R DLLMessages.res} to the Sourcecode of the DLL. You need noting more. This will be the DLL which is in use by the Windows Eventlog, when displaying the Records you have added. Please place the DLL on the Location you will specify in the Registry (see point 2), in this case %SystemRoot%. Remember, that this DLL is in use, when the Eventlog is open, so you cannot compile then.


2. Register your Application in the Eventlog:
You need to register your Application in the Registry, by adding the following registry Entries:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\My Application Name]
"EventMessageFile"="%SystemRoot%\\MyRessourceDLL.dll"
"TypesSupported"=dword:00000007
"CategoryCount"=dword:00000002
"CategoryMessageFile"="%SystemRoot%\\MyRessourceDLL.dll"


EventMessageFile specifies the Location of the Message File, which contains Strings for the Events
CategoryMessageFile specifies the Location of the Message File, which contains Strings for the Event Categories
CategoryCount specifies, how much categories are in the Message File

3. Add a Record to the Eventlog with Delphi

The following Code can be used to add a new Record to the Eventlog with a single String


var
//From Caller
StringToAdd:
String;
//Handle to Eventlog
hEventLog:
THandle;
//Pointer to hold the passed String
p: PChar;
//Variables to hold Information for the Eventlog
EventID:
Word;
CategoryID:
Word;
begin
hEventLog := RegisterEventSource(nil, PChar(My Application'));
if hEventLog > 0 then
begin
p := PChar(StringToAdd);
ReportEvent(
hEventLog,
EVENTLOG_INFORMATION_TYPE, // Event Type
CategoryID, // Event Category ID --> e.g. 1 aka 'Database Connection Error'
EventID, // Event ID --> e.g. 3 aka 'Failed to connect to database Server %1'
nil, // User SID (optional)
1, // Number of strings
0, // Size of Binary Data
@p, // String to be merged with Text in Ressource DLL --> e.g. 'DBSERVER'
nil // Address of Binary Data
);
//Disonnect from Eventlog
DeRegisterEventSource(hEventLog);
end;
end.

You can also add multiple Strings to the Eventlog with the following Code

var
//From Caller
StringToAdd1, StringToAdd2:
String;
//Handle to Eventlog
hEventlog:
THandle;
//Pointer to hold the passed Strings
p: array[0..1] of PChar;
//Variables to hold Information for the Eventlog
EventID:
Word;
CategoryID:
Word;
begin
hEventLog := RegisterEventSource(nil, PChar(My Application'));
if hEventLog > 0 then
begin
p[0]:= PChar(StringToAdd1); e.g. 'DBSERVER'
p[1]:= PChar(StringToAdd2); e.g. '0x80004005'
ReportEvent(
hEventLog,
EVENTLOG_INFORMATION_TYPE, // Event Type
CategoryID, // Event Category ID --> e.g. 2 aka Server Connection Error
EventID, // Event ID --> e.g. 6 aka 'Failed to connect to Server %1 HR: %2'
nil, // User SID (optional)
2, // Number of strings
0, // Size of Binary Data
@p, // Array of Strings to merge with Message
nil // Address of Binary Data
);
//Disonnect from Eventlog
DeRegisterEventSource(hEventLog);
end;
end.

The Delphi Sourcecode can be found for Download
here