先日ofZさんにレスいただき、下記のようにReadEventLogで全てを読み込み
処理したいのですが、eventID= 6005 or 6006が読み込めたり、飛ばされたりで思った処理ができません。
recordNumberとか確認しましたが、やはりシーケンシャルではありませんでした。私にはまったく判りません。
これはどうしようもないでしょうか?
環境はXP、D7です。
TButtonとTMemoをおいて
type
// Internal structure for event logs
PEVENTLOGRECORD = ^EVENTLOGRECORD;
EVENTLOGRECORD = packed record
Length : DWORD;
Reserved : DWORD;
RecordNumber : DWORD;
TimeGenerated : DWORD;
TimeWritten : DWORD;
EventID : DWORD;
EventType : WORD;
NumStrings : WORD;
EventCategory : WORD;
ReservedFlags : WORD;
ClosingRecordNumber : DWORD;
StringOffset : DWORD;
UserSidLength : DWORD;
UserSidOffset : DWORD;
DataLength : DWORD;
DataOffset : DWORD;
// Then follows Variant Area .....
// TCHAR SourceName[]
// TCHAR Computername[]
// SID UserSid
// TCHAR Strings[]
// BYTE Data[]
// CHAR Pad[]
// DWORD Length;
end;
TEventLogRecord =EVENTLOGRECORD;
const
EVENTLOG_SEQUENTIAL_READ = 1;
EVENTLOG_SEEK_READ = 2;
EVENTLOG_FORWARDS_READ = 4;
EVENTLOG_BACKWARDS_READ = 8;
function TimeGeneratedToDateTime(aTimeGenerated: DWORD): TDateTime;
const
SecondPerDay = 60 * 60 * 24; //一日の秒数
begin
Result := EncodeDate(1970,1,1) + EncodeTime(9,0,0,0);
Result := ((Result * SecondPerDay) + aTimeGenerated) / SecondPerDay;
end;
procedure TForm1.Button2Click(Sender: TObject);
const
//最新のログから順次読み込む
READ_FLAG= EVENTLOG_SEQUENTIAL_READ or EVENTLOG_BACKWARDS_READ;
var
eLogHandle: THandle;
logCount: DWORD;
i: Integer;
eventID: Integer;
pBuf: PEventLogRecord;
bufSize: Integer;
readNum, readNeed: DWORD;
lastLogOn: TDateTime;
lastLogOut: TDateTime;
begin
eLogHandle := OpenEventLog(nil, 'System');
//クリア
lastLogOn := 0;
lastLogOut := 0;
Memo1.Lines.Clear;
if eLogHandle > 0 then begin
//ログ数を取得
if not GetNumberOfEventLogRecords(eLogHandle, logCount) then
logCount := 0;
//メモリ確保
bufSize := SizeOf(TEventLogRecord);
pBuf := AllocMem(bufSize);
for i := 1 to logCount do begin
{読み込み}
if not ReadEventLog(eLogHandle, READ_FLAG,
logCount - 1, pBuf, bufSize, readNum, readNeed) then begin
if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin
//メモリの再割り当て
bufSize := readNeed;
ReallocMem(pBuf, bufSize);
if not ReadEventLog(eLogHandle, READ_FLAG,
logCount - 1, pBuf, readNeed, readNum, readNeed) then begin
//失敗
Break;
end;
end
else begin
//失敗
Break;
end;
end;
eventID := pBuf^.EventID AND $FFFF;
if eventID = 6005 then begin
lastLogOn := TimeGeneratedToDateTime(pBuf^.TimeGenerated);
Memo1.Lines.Add('最終ログイン:' + FormatDateTime('yyyy/mm/dd hh:nn:ss', lastLogOn));
end
else if eventID = 6006 then begin
lastLogOut := TimeGeneratedToDateTime(pBuf^.TimeGenerated);
Memo1.Lines.Add('最終ログオフ:' + FormatDateTime('yyyy/mm/dd hh:nn:ss', lastLogOut));
end;
end;
//メモリ開放
FreeMem(pBuf);
//ログを閉じる
CloseEventLog(eLogHandle);
end;
end;
たぶんだけど、 ReadEventLog に大きなメモリバッファを割り当てすると、
複数のイベントが読み込まれるんじゃないだろうか?
MSDNを読んでみると、以下のように記載されています。
> nNumberOfBytesToRead
>バッファのサイズをバイト単位で指定します。指定したバッファに入る、
> できるだけ多くの完全なログエントリが読み取られます。バッファに空き
> があっても、エントリの一部が読み取られることはありません。
http://msdn.microsoft.com/ja-jp/library/cc428978.aspx
そんなわけで、以下の処理を追加することが対策と思われます。
1)ReadEventLog で、複数のイベントを読むことができた場合に対応する。
2)一回目のReadEventLogは、必ずERROR_INSUFFICIENT_BUFFER になるように
2-A)forループの最初に、必ずバッファサイズを小さくする処理を入れる
(ReallocMemで小さくしてしまう)
2-B)ReadEventLogはバッファサイズを小さく与える
実際のバッファサイズより大きいサイズが必要な時だけReallocMemで大きくする
試していないので、うまくいったら報告してください。
ちなみに元スレはこれです
https://www.petitmonte.com/bbs/answers?question_id=6124
ofZさん、早速かつ何度も申し訳ございません。
ご指摘の通り修正したところバッチリでした。
確かに他のスレで可変長だから、ワザとエラーとするとかありました。
ほんとに感謝です。
有難うございました。
ツイート | ![]() |