How To: Reading the Windows NT event log
Posted: (EET/GMT+2)
How To: Reading the Windows NT event log
Level: Delphi, Win32 Intermediate
The Windows NT event log contains events recorded both by the system and
user applications. You can see the events in the event log using the Event
Viewer, by choosing Start/Programs/Administrative Tools/Event Viewer.
In this How To you will learn how to read the event log and scan for the
system startup event (event ID 512). The sample application also creates
an icon to the task tray. (For more information about this, see
Creating simple task tray apps.) When you move
the mouse pointer over the icon, you will see for how long your NT system
has been up and running.
Reading the event log
To read the event log, three Win32 API functions are needed. The first function, OpenEventLog opens a handle to the event log. ReadEventLog is used to read the events, and finally the code closes the handle to the log by calling CloseEventLog.
The following code does just this:
Procedure ScanEventLogForStartupEvent;
Var
Log : THandle;
Buf : Array[0..5000-1] of Char;
BytesRead,MinBytes,Ofs : Integer;
Begin
Log := OpenEventLog(nil,'Security');
While (ReadEventLog(Log,EventLog_Backwards_Read Or EventLog_Sequential_Read,0,
@Buf,SizeOf(Buf),BytesRead,MinBytes)) do Begin
Ofs := 0;
While (BytesRead > 0) do Begin
With PEventLogRecord(@Buf[Ofs])^do Begin
If (EventID = 512) Then Begin { "Windows NT is starting up." }
SystemStartupTime := (TimeGenerated / (60*60*24))+25569.08333333333;
CloseEventLog(Log);
Exit;
End;
Inc(Ofs,Length);
Dec(BytesRead,Length);
End;
End;
End;
CloseEventLog(Log);
MessageBox(0,'Cannot find system startup event from event log.','UpTime',mb_IconError+mb_OK);
Halt(2);
End;
Here, the event log is read "backwards" so that we first read the newest
events. When we find the system startup event (ID 512), we must convert the
event logging time (given in seconds since 1st January, 1970) into a
TDateTime which Delphi uses. This is done by dividing by the constant 86400
(seconds in a day) and addind a "magic" constant. After the data is in a
TDateTime, it is easy to calculate the "up time" with the code:
RunTime := Now-SystemStartupTime+1;Note that the two constants, EventLog_Backwards_Read and EventLog_Sequential_Read are not defined in Delphi's Windows.PAS. Instead, I've converted the constants from WINNT.H as follows:
Const EventLog_Sequential_Read = $1; EventLog_Backwards_Read = $8;Also, the same applies to the TEventLogRecords. It is defined as follows:
Type
PEventLogRecord = ^TEventLogRecord;
TEventLogRecord = Record
Length : Integer;
Reserved : Integer;
RecordNumber : Integer;
TimeGenerated : Integer;
TimeWritten : Integer;
EventID : Integer;
EventType : Word;
NumStrings : Word;
EventCategory : Word;
ReservedFlags : Word;
ClosingRecordNumber : Integer;
StringOffset : Integer;
UserSidLength : Integer;
UserSidOffset : Integer;
DataLength : Integer;
DataOffset : Integer;
{ optional data follows }
End;
Conclusion
Reading the event log is quite easy with some help of the C-language header files. Converting the data types and constants is not hard, but I hope Inprise will do better work next time.