[Lazarus] RE : Read Windows EventLog...

Ludo Brands ludo.brands at free.fr
Sat Sep 10 20:32:23 CEST 2011


> 
> Hello team
> 
> Somebody know how read from Windows EventLog with Free Pascal 
> and Lazarus?
> 
> Liyuan
> 
> 

A quick and dirty program:


program dumpEventLog;

uses windows,sysutils,classes;


procedure geteventlog(const provider: string; var sl:TStringList) ;

var hnd:HANDLE;
  lpBuffer: Pointer;
  pnBytesRead, pnMinNumberOfBytesNeeded: DWORD;
  pRecord: PEVENTLOGRECORD;
  eventtype,sdate,computer,source,data:string;
  user,domain:array [0..255] of char;
  userlen,domlen:dword;
  datestart:TDateTime;
  peUse: SID_NAME_USE;
  p:pchar;
  i:integer;
begin
  hnd:=OpenEventLog(nil,pchar(provider));
  if hnd<>0 then
    begin
    datestart:=EncodeDate(1970,1,1);
    getmem(lpbuffer,$10000);
    while ReadEventLog(hnd,EVENTLOG_SEQUENTIAL_READ or
EVENTLOG_BACKWARDS_READ, 0,
      lpBuffer, $10000, pnBytesRead, pnMinNumberOfBytesNeeded) do
      begin
      pRecord:=lpBuffer;
      while pRecord< lpBuffer+pnBytesRead do
        begin
        case pRecord^.EventType of
           EVENTLOG_ERROR_TYPE       :eventtype:='Error';
           EVENTLOG_WARNING_TYPE     :eventtype:='Warning';
           EVENTLOG_INFORMATION_TYPE :eventtype:='Information';
           EVENTLOG_AUDIT_SUCCESS    :eventtype:='Audit Success';
           EVENTLOG_AUDIT_FAILURE    :eventtype:='Audit Failure';
           end;
        sdate:=DateTimeToStr(datestart+pRecord^.TimeGenerated/24/3600);
        if pRecord^.UserSidLength=0 then
          begin
          user:='N/A';
          domain:='N/A';
          end
        else
          begin
          userlen:=256;
          domlen:=256;
 
LookUpAccountSID(Nil,PSID(pointer(pRecord)+pRecord^.UserSidOffset),user,user
len,domain,domlen,peUse);
          end;
        source:=pchar(PSID(pointer(pRecord)+sizeof(TEventLogRecord)));
 
computer:=pchar(PSID(pointer(pRecord)+sizeof(TEventLogRecord)+length(source)
+1));
        data:='';
        p:=pchar(pointer(pRecord)+pRecord^.StringOffset);
        for i:=1 to pRecord^.NumStrings do
          begin
          data:=data+p+';';
          p:=p+strlen(p)+1;
          end;
        sl.Add(format('Number: %d  Date: %s ID: %d  Type: %s Category: %d
User: %s Domain: %s Computer: %s Source %s Data: %s',
           [pRecord^.RecordNumber,sdate,pRecord^.EventID and $FFFF ,
eventtype ,pRecord^.EventCategory ,
           user,domain,computer,source,data]));
        pRecord:=PEVENTLOGRECORD(pointer(pRecord)+pRecord^.Length);
        end;
      end;
    freemem(lpbuffer);
    CloseEventLog(hnd);
    end;
end;

var
  sl:TStringList;
  i:integer;
begin
  sl:=TStringList.create;
  geteventlog('Security',sl);
  for i:=0 to sl.Count-1 do
    writeln(sl[I]);
  sl.destroy;
end.

Change Security to Application to System or ... to get the other logs.

This program just dumps the data strings unformated. To get the nice error
message as displayed in the event viewer, quite some more work is needed.
The data in the eventlog are just the variable parts in a formatted string.
To get the format string you need to take the source of the event (say
crypt32 in the Application log), read the registry value
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\cr
ypt32\EventMessageFile which is the filename of a dll, load that library,
lookup the resource with ID EventID and substitute the data in the format
string.

Ludo





More information about the Lazarus mailing list