c++event-logreadeventlog

Why Does My Vector<PEVENTLOGRECORD> Mysteriously Get Cleared?


I am making a program that reads and stores data from Windows EventLog files (.evt) in C++. I am using the calls OpenBackupEventLog(ServerName, FileName) and ReadEventLog(...). Also using this: PEVENTLOGRECORD

Anyway, without supplying all of the code, here is the basic idea:
1. I get a handle to the .evt file using OpenBackupEventLog() and passing in a file name.
2. I then use ReadEventLog() to fill up a buffer with an unknown number of EventLog messages.
3. I traverse through the buffer and add each message to a vector
4. I keep filling up buffers (repeat steps 2 and 3) until I reach the end of the file.

Here is my code for filling the vector:

vector<EVENTLOGRECORD> allRecords;
while(_status == ERROR_SUCCESS)
{
   if(!ReadEventLog(...))
       CheckStatus();
   else
       FillVectorFromBuffer(allRecords)
}

// Function FillVectorFromBuffer
FillVectorFromBuffer(vector(EVENTLOGRECORD) &allRecords)
{
   int bytesExamined = 0;
   PBYTE pRecord = (PBYTE)_lpBuffer;    // This is one of the params in ReadEventLog()
   while(bytesExamined < _pnBytesRead)  // Another param from ReadEventLog
   {
      EVENTLOGRECORD currentRecord = (EVENTLOGRECORD)(pRecord);
      allRecords.push_back(currentRecord);
      pRecord += currentRecord->Length;
      bytesExamined += currentRecord->Length;
   }
}

Anyway, whenever I run this, it will get all the EventLogs in the file, and the vector will have everything I want it to. But as soon as this line:

if(!ReadEventLog())

gets called and returns true (aka ReadEventLog() returns false), then every field in my vector gets set to zero.

The vector will still contain the correct number of elements, it's just that all of the fields in the PEVENTLOGRECORD struct are now zero.

Anyone with better debugging experience have any ideas?

Thanks.

Edit: I have updated the code per Michael Burr's suggestion. The above code now eliminates the original problem I was having.

Edit 2: Addressing Michael Burr's other suggestion: Because of the variable portion of the EVENTLOGRECORD, I will make a custom struct that has the EVENTLOGRECORD plus a few other variables that I am interested in:

struct CustomRecord
{
   EVENTLOGRECORD recordHeader;
   string sourceName;
   string computerName;
   string message;
};

Pulling out the variable portions is no trivial task, but here is an excellent example to get you started: Querying for Event Information


Solution

  • I'd guess that your vector (which I think should read as vector<PEVENTLOGRECORD>, not vector(PEVENTLOGRECORD)) contains pointers to the data rather than copies of the data. I think that whatever owns the actual data is releasing it when the ReadEventLog() indicates that there is no more data.

    One possible fix is that you should store the data itself in the vector rather than the pointers. Make the vector a vector<EVENTLOGRECORD> and store the dereferenced contents of the PEVENTLOGRECORD pointer into the vector (which should create a copy) instead of the pointer itself:

    allRecords.push_back(*currentRecord);
    

    Update: On closer look in MSDN, the EVENTLOGRECORD is one of those nasty variable length structs where the compiler knows about only the 'header' portion. The variable length data follows that header, but strictly speaking is not part of the struct as far as the compiler is concerned. So a vector<EVENTLOGRECORD> won't capture the variable part of the data. You'll need to come up with a custom class that can be initialized with a PEVENTLOGRECORD and knows how to properly deal with the variable data, or you'll need to copy the struct and it's variable data into a properly sized, dynamically-allocated array of bytes and store a pointer to that allocated block (but don't free the block until the vector is done with with it - a smart pointer could help here).

    Coming up with the class that can intelligently deal with the event log record data might be a bit of work up front, but I'd guess that work would pay off in the long run if you're doing any significant work with the records. You might find a class on the net that can be used or used as a starting point for your own (a quick search found CEventLogRecord from http://www.naughter.com/serv.html, for example).