電源オン、オフの時間の取得2

解決


ちょく  2009-02-25 21:15:50  No: 33461

先日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;


ofZ  2009-02-25 23:15:57  No: 33462

たぶんだけど、 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


ちょく  2009-02-26 00:17:43  No: 33463

ofZさん、早速かつ何度も申し訳ございません。
ご指摘の通り修正したところバッチリでした。
確かに他のスレで可変長だから、ワザとエラーとするとかありました。
ほんとに感謝です。
有難うございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加