Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Delphi Event Log messages

1,616 views
Skip to first unread message

Ignacio Vazquez

unread,
Jun 23, 2003, 11:42:50 AM6/23/03
to
Is it just me, or did I see somewhere a procedure that can write to Delphi's
Event Log?

If not, what would be another similar prefab solution that doesn't require
going through the Win32 API?

Thanks,
Ignacio

Jason

unread,
Jun 23, 2003, 12:07:49 PM6/23/03
to

"Ignacio Vazquez" <ivazquezATorioncommunications.com> wrote in message
news:3ef7...@newsgroups.borland.com...

Here is an excellent document on the subject. Let me know when you figure out how to
read..

Writing Messages

to the Microsoft

Event Log using

Delphi

FMI Solutions

© FMI Solutions 2002 Page 1

An application can write to the event log by using the following API routines. For

details on the parameters of these functions see the API documentation.

. RegisterEventSource - This opens a handle to the event log, on a local or

remote machine.

. ReportEvent - This is used to actually write the event.

To write to the event log in a simple fashion simply involves calling Register event

source with the computer name (UNC) of the event log you wish to use (nil for

local) and the event source name. The event source name is typically the name of

the application, but can be anything descriptive. Once an event source has been

registered, events can be written by calling ReportEvent, using the handle

returned by RegisterEventSource. For example :

VAR EventLog : Thandle;

.

.

EventLog := RegisterEventSource(nil,PChar('MyApplication'));

.

.

VAR MyMsg:Array[0..2] Of PChar;

.

.

MyMsg[0]:= 'A test event message';

ReportEvent(EventLog,EVENTLOG_INFORMATION_TYPE,0,0,nil,1,0,@MyMsg,n

il);

However the event text written to the event log will be prefixed by

"The description for Event ID ( 0 ) in Source (MyApplication ) cannot be

found. The local computer may not have the necessary registry information or

message DLL files to display messages from a remote computer. The following

information is part of the event:"

(Nb : This message is specific to Windows 2000 and will appear slightly differently

on other Windows platforms).

To eliminate this text, it is necessary to enter some registry values as follows and

define string resources (this can be done in any component of your software, not

necessarily the application which is reporting the events. The relevant registry

entries are described below. Code examples assume that the resources for event

messages and categories are located in the same executable that is writing the

events, category keys are optional.

The reason for these registry entries and the string resources is that the event log

uses the string an application writes to it as a format argument, and it needs to

know where the format specifier for the this string is. Also category information

can be specified in a file for the event viewer to user, rather that just display a

number or the typical "None". So, the most simple format specifier is %1, which

will just output the input string. For more information on format specifiers and

arguments see the API documentation for FormatMessage.

© FMI Solutions 2002 Page 2

Registry Entries

Create the following registry key :

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Applicatio

n\<AppName>

The application name used in the above registry key must match the source

name used when calling RegisterEventSource, because the event viewer will use

this source name to find the registry entries below.

Create the following values:

Value Name Type Description

CategoryCount

(Optional) :Integer

The number of event categories

you have (this is a max index not

really a count and does not seem to

cause a problem if it does not

match the number of categories

actually defined)

CategoryMessageFile

(Optional)

String

The file which contains the category

text string resources

EventMessageFile String

The file which contains the event

text string resources

TypesSupported Integer Types of events allowed

Example code to create registry entries:

Top of Form

VAR Reg : TRegistry;

RegKey : String;

AppPath : String;

AppName : String;

NumCategories : Integer;

begin

Reg := TRegistry.Create;

try

AppPath := Application.ExeName;

AppName := 'pEventLogging';

Delete(AppName,Length(AppName)-4,4); //Remove Extension

NumCategories := 2;

RegKey :=

Format('SYSTEM\CurrentControlSet\Services\Eventlog\Application\%s',[AppName

]);

Reg.RootKey := HKEY_LOCAL_MACHINE;

Reg.OpenKey(RegKey,True);

Reg.WriteString('CategoryMessageFile',AppPath); //Own filename

Reg.WriteString('EventMessageFile',AppPath); //Own filename

Reg.WriteInteger('CategoryCount',NumCategories); //Max category index

Reg.WriteInteger('TypesSupported',EVENTLOG_SUCCESS or

EVENTLOG_ERROR_TYPE or

EVENTLOG_WARNING_TYPE or

EVENTLOG_INFORMATION_TYPE); //Allow all types

Reg.CloseKey;

EventLog := RegisterEventSource(nil,PChar(AppName));

finally

Reg.Free;

end; //try..finallyVAR Reg : TRegistry;

© FMI Solutions 2002 Page 3

RegKey : String;

AppPath : String;

AppName : String;

NumCategories : Integer;

begin

Reg := TRegistry.Create;

try

AppPath := Application.ExeName;

AppName := 'MyApplication';

NumCategories := 2;

RegKey :=

Format('SYSTEM\CurrentControlSet\Services\Eventlog\Application\%s',[AppName

]);

Reg.RootKey := HKEY_LOCAL_MACHINE;

Reg.OpenKey(RegKey,True);

Reg.WriteString('CategoryMessageFile',AppPath); //Own filename

Reg.WriteString('EventMessageFile',AppPath); //Own filename

Reg.WriteInteger('CategoryCount',NumCategories); //Max category index

Reg.WriteInteger('TypesSupported',EVENTLOG_SUCCESS or

EVENTLOG_ERROR_TYPE or

EVENTLOG_WARNING_TYPE or

EVENTLOG_INFORMATION_TYPE);

Reg.CloseKey;

EventLog := RegisterEventSource(nil,PChar(AppName));

finally

Reg.Free;

end; //try..finally

Message and category resources

The above information entered in the registry informs the event log of where to

look for message strings and category strings based on the source name that an

application uses to write to the event log. So since we have told the event log to

look at our application we need to include these resources in our executable. This

involves creating a message table containing the strings. This process involves

the following steps:

. Writing a message table source file (a .mc file).

. Compiling the .mc file with Microsoft's message compiler.

. Link the resulting information into your Delphi application.

There are examples and information on writing .mc files in the Windows platform

SDK documentation and on various websites, including MSDN, however the

documentation is not very clear so below is an example of the minimum

information required in a message table source file :

;//Example Message source file exmess.mc

MessageId=0

Language=English

%1

.

MessageId=1

Language=English

Category1

.

MessageId=2

Language=English

Category2

© FMI Solutions 2002 Page 4

.

Lines starting with ;// are comments and are not compiled. This example file

contains three string resources, one event message format specifier and two

category resources, although it could have contained just the first resource. Each

resource is separated by a single full stop on it's own line, and the file is

terminated by a full stop on it's own line - if there is not a line break after the

last full stop the file will not compile.

The fist line of a resource specifies it's MessageID (index), which an application

will use to refer to the string later. The next line specifies the language of the

resource, in this case "English" specifies international English, the default

language of Windows platforms. For information on multilingual resources see the

message compiler help. The last line specifies the actual string resource text.

In the case of resource 0 the text is "%1", which means that the output will be

the same as the input. The message could be prefixed with the text "An Event

Message" by making the string resource text "An Event Message %1". More

information on format strings can be found in the API documentation for

FormatMessage and in the Message Compiler help.

Resources detailing categories do not take format arguments. As can be seen in

the example .mc file we have defined two categories "Category1" and

"Category2".

The next stage is to compile the .mc file using the Microsoft Message Compiler

(MC.exe), which can be obtained from Microsoft, and is part of the Windows

Platform SDK. The example .mc file named "exmess.mc" can be compiled from

the command line as follows :

mc exmess.mc

This will produce three files exmess.rc, bin00001.msg and exmess.h. Exmess.h

can be used as a header file referencing the message resources by their symbolic

name if specified (not included in the example). The .bin file is a compiled binary

message table resource, and the .rc is a windows resource file. This can be

compiled into a .res Delphi resource file using the Delphi resource compiler

(brcc32.exe) or more simply can be directly added to the Delphi project by just

adding the file in the project manager, where Delphi will automatically compile it

during the build process.

Writing events with categories

Once an application has the resources linked in, and the relevant registry entries,

or code to create them, the application can write events to the event log as

previously described, but without the error prefix and can also include a category

index:

VAR EventLog : Thandle;

.

.

EventLog := RegisterEventSource(nil,PChar('MyApplication'));

.

.

VAR MyMsg:Array[0..2] Of PChar;

.

© FMI Solutions 2002 Page 5

.

MyMsg[0]:= 'A test event message';

ReportEvent(EventLog,EVENTLOG_INFORMATION_TYPE,1,0,nil,1,0,@MyMsg,n

il);

The above code will now write an event to the event log, with the text "A test

event message" and because of the 1 following the EventLogType parameter, it

will be a "Category1" event.

This is achieved because by specifying 0 as the event id, which is mapped to the

format specifier in resource 0 ("%1"), passing "A test event message" as a

parameter which will output "A test event message". Similarly the category is

specified as 1 which will map to the text in resource 1 ("Category1").

The Event Log maintains a "live link" to the message and category resource files

specified in the registry, which means that when a user wishes to view an event

log the Event Viewer will access the resource files to display the event details.

This means that if you create a number of events using a specific resource file

and then change the values in the resource file and refresh the Event Viewer, the

event text and categories will also change depending on the resource changes.

Similarly if the resource file is deleted or the registry entries are removed or

corrupted then the event log will not be able to access the resources and will

display the error message as detailed at the beginning of this document as a

prefix to the event text and the category index will be displayed as the category.

Jason

unread,
Jun 23, 2003, 12:09:07 PM6/23/03
to

"Ignacio Vazquez" <ivazquezATorioncommunications.com> wrote in message
news:3ef7...@newsgroups.borland.com...


oops sorry, did not notice you said "Delphi's" event log..

Rob Kennedy

unread,
Jun 23, 2003, 12:07:52 PM6/23/03
to
Ignacio Vazquez wrote:
> Is it just me, or did I see somewhere a procedure that can write to Delphi's
> Event Log?

OutputDebugString

> If not, what would be another similar prefab solution that doesn't require
> going through the Win32 API?

Oh, sorry. ODS is an API function, but its entire purpose is to send
status strings to the debugger. If there's a Delphi library function
that does the same thing, then I'm sure it was introduced for Kylix
compatibility and that the Windows implementation of it calls ODS.

You can also use an advanced breakpoint. You can set a message to send
to the log, and you can also indicate an expression to evaluate and have
the result sent to the log.

--
Rob


Ignacio Vazquez

unread,
Jun 23, 2003, 1:29:58 PM6/23/03
to
Found it. JclDebug.Trace found in JCL.

See, I'm not nuts. Or rather, not THAT nuts ;)

http://sourceforge.net/projects/jcl/

Cheers,
Ignacio

Ignacio Vazquez

unread,
Jun 23, 2003, 2:04:18 PM6/23/03
to
"Ignacio Vazquez" <ivazquezATorioncommunications.com> wrote in message
news:3ef73916$1...@newsgroups.borland.com...

> Found it. JclDebug.Trace found in JCL.

Well Rob, you were right. It is in fact a wrapper for ODS. And Delphi's
Event Log traps ODS messages, so it's all good anyways.

Cheers,
Ignacio

0 new messages