Index: t/RT61484.t
===================================================================
--- t/RT61484.t (revision 0)
+++ t/RT61484.t (revision 0)
@@ -0,0 +1,98 @@
+use strict;
+use warnings;
+
+use Test::More tests => 122;
+
+
+{
+ package TestLogSeq;
+ use Win32::EventLog;
+
+ sub new
+ {
+ my $class = shift;
+ #$class = (ref $class) ? (ref $class) : $class;
+ my $log = Win32::EventLog->new('Application', '');
+ Test::More::isa_ok($log, 'Win32::EventLog', "$class log");
+ return bless {
+ log => $log,
+ flags => (EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ),
+ }, $class;
+ }
+
+ sub _next_offset
+ {
+ 0
+ }
+
+ sub read
+ {
+ my $self = shift;
+ local $Win32::EventLog::GetMessageText = 1;
+ my ($flags, $offset) = ($self->{flags}, $self->_next_offset);
+ #printf "# %s: 0x%X %d\n", (ref $self), $flags, $offset;
+ $self->{log}->Read($flags, $offset, my $entry) or die "Read failure";
+ Test::More::is(ref $entry, 'HASH', "entry is HASHREF");
+ Test::More::ok(exists $entry->{RecordNumber}, "entry has RecordNumber");
+ if ($offset > 1) {
+ Test::More::is($entry->{RecordNumber}, $offset, "RecordNumber is $offset");
+ }
+ return $entry;
+ }
+
+ sub DESTROY
+ {
+ $_[0]->{log}->Close;
+ }
+}
+
+{
+ package TestLogSeek;
+ use Win32::EventLog;
+ use Test::More;
+
+ our @ISA = qw(TestLogSeq);
+
+ sub new
+ {
+ my $class = shift;
+ my $self = TestLogSeq::new($class, @_);
+ $self->{flags} = (EVENTLOG_SEEK_READ | EVENTLOG_BACKWARDS_READ);
+
+ my $log = $self->{log};
+
+ my ($oldest, $lastRec);
+ $log->GetOldest($oldest);
+ $log->GetNumber($lastRec);
+ $self->{offset} = $oldest + $lastRec;
+
+ return $self;
+ }
+
+ sub _next_offset
+ {
+ return --$_[0]->{offset};
+ }
+}
+
+
+sub check_entries
+{
+ my ($a, $b) = @_;
+ is(scalar localtime $a->{TimeGenerated}, scalar localtime $b->{TimeGenerated}, 'check TimeGenerated is "'.scalar(localtime $a->{TimeGenerated}).'"');
+ #foreach my $attr (qw(RecordNumber Computer Source EventType Category EventID Message)) {
+ foreach my $attr (qw(RecordNumber)) {
+ is($a->{$attr}, $b->{$attr}, "check $attr is $b->{$attr}");
+ }
+}
+
+
+my $log_seq = TestLogSeq->new;
+my $log_seek = TestLogSeek->new;
+
+foreach (1..15) {
+ pass "== Read $_ ==";
+ check_entries($log_seq->read, $log_seek->read);
+}
+
+# vim:set et sw=4 sts=4:
Index: Changes
===================================================================
--- Changes (revision 502)
+++ Changes (working copy)
@@ -1,5 +1,14 @@
Revision history for Perl extension Win32::EventLog.
+0.077
+ - fix for skipped record when reading in SEQUENTIAL mode
+ (RT#61484) by Olivier Mengue
+ - the OFFSET argument is now completely ignored in SEQUENTIAL read
+ as in the underlying Win32 implementation. A '0' value previously
+ had a special behaviour which bypassed the cache and so gave
+ unpredictable results. Olivier Mengue.
+ - added test for RT#61484 by Olivier Mengue
+
0.076 Wed Jul 02 2008 (Jan Dubois)
- Make sure the regression tests are properly skipped on Win95
Index: EventLog.xs
===================================================================
--- EventLog.xs (revision 502)
+++ EventLog.xs (working copy)
@@ -26,9 +26,8 @@
BOOL wideEntries; /* has unicode character entries */
LPBYTE BufPtr; /* pointer to data buffer */
DWORD BufLen; /* size of buffer */
- DWORD NumEntries; /* number of entries in buffer */
- DWORD CurEntryNum; /* next entry to return */
EVENTLOGRECORD *CurEntry; /* point to next entry to return */
+ EVENTLOGRECORD *EndEntry; /* point to after the last entry read */
DWORD Flags; /* read flags for ReadEventLog */
} EvtLogCtlBuf, *lpEvtLogCtlBuf;
@@ -278,12 +277,14 @@
lpEvtLog = SVE(handle);
if ((lpEvtLog != NULL) && (lpEvtLog->dwID == EVTLOGID)) {
DWORD NumRead, Required;
- if (Flags != lpEvtLog->Flags) {
+ if ( (Flags != lpEvtLog->Flags)
+ || (lpEvtLog->CurEntry >= lpEvtLog->EndEntry)
+ || (((Flags & EVENTLOG_SEEK_READ) == EVENTLOG_SEEK_READ) && Record != lpEvtLog->CurEntry->RecordNumber)) {
/* Reset to new read mode & force a re-read call */
lpEvtLog->Flags = Flags;
- lpEvtLog->NumEntries = 0;
+ lpEvtLog->EndEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
}
- if ((lpEvtLog->NumEntries == 0) || (Record != 0)) {
+ if (lpEvtLog->CurEntry >= lpEvtLog->EndEntry) {
redo_read:
result = ReadEventLogA(lpEvtLog->hLog, Flags, Record,
lpEvtLog->BufPtr, lpEvtLog->BufLen,
@@ -291,9 +292,9 @@
lpEvtLog->wideEntries = FALSE;
if (result)
- lpEvtLog->NumEntries = NumRead;
+ lpEvtLog->EndEntry = (EVENTLOGRECORD*) (lpEvtLog->BufPtr + NumRead);
else {
- lpEvtLog->NumEntries = 0;
+ lpEvtLog->EndEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
if (Required > lpEvtLog->BufLen
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
@@ -302,12 +303,12 @@
goto redo_read;
}
}
- lpEvtLog->CurEntryNum = 0;
- lpEvtLog->CurEntry = (EVENTLOGRECORD*)lpEvtLog->BufPtr;
+ lpEvtLog->CurEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
}
- if (lpEvtLog->CurEntryNum < lpEvtLog->NumEntries) {
+ if (lpEvtLog->CurEntry < lpEvtLog->EndEntry) {
EVENTLOGRECORD *LogBuf;
+ /*printf("# CurEntryNum: %d NumEntries: %d\n", lpEvtLog->CurEntryNum, lpEvtLog->NumEntries);*/
LogBuf = lpEvtLog->CurEntry;
SETPVN(3, (char*)LogBuf, LogBuf->Length);
if (lpEvtLog->wideEntries) {
@@ -348,13 +349,7 @@
SETPVN(8, ((LPBYTE)LogBuf)+LogBuf->StringOffset, LogBuf->DataOffset-LogBuf->StringOffset);
/* to next entry in buffer */
- lpEvtLog->CurEntryNum += LogBuf->Length;
lpEvtLog->CurEntry = (EVENTLOGRECORD*)(((LPBYTE)LogBuf) + LogBuf->Length);
- if (lpEvtLog->CurEntryNum == lpEvtLog->NumEntries) {
- lpEvtLog->NumEntries = 0;
- lpEvtLog->CurEntryNum = 0;
- lpEvtLog->CurEntry = NULL;
- }
RETVAL = TRUE;
}
}
@@ -684,9 +679,8 @@
if (lpEvtLog->hLog) {
/* return info... */
lpEvtLog->dwID = EVTLOGID;
- lpEvtLog->NumEntries = 0;
- lpEvtLog->CurEntryNum = 0;
- lpEvtLog->CurEntry = NULL;
+ lpEvtLog->CurEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
+ lpEvtLog->EndEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
lpEvtLog->Flags = 0;
hEventLog = (size_t)lpEvtLog;
RETVAL = TRUE;
@@ -718,9 +712,8 @@
if (lpEvtLog->hLog) {
/* return info... */
lpEvtLog->dwID = EVTLOGID;
- lpEvtLog->NumEntries = 0;
- lpEvtLog->CurEntryNum = 0;
- lpEvtLog->CurEntry = NULL;
+ lpEvtLog->CurEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
+ lpEvtLog->EndEntry = (EVENTLOGRECORD*) lpEvtLog->BufPtr;
lpEvtLog->Flags = 0;
hEventLog = (size_t)lpEvtLog;
RETVAL = TRUE;
Index: EventLog.pm
===================================================================
--- EventLog.pm (revision 502)
+++ EventLog.pm (working copy)
@@ -9,7 +9,7 @@
use strict;
use vars qw($VERSION $AUTOLOAD @ISA @EXPORT $GetMessageText);
-$VERSION = '0.076';
+$VERSION = '0.077';
require Exporter;
require DynaLoader;
@@ -276,6 +276,21 @@
The Read() method read an EventLog entry from the EventLog represented
by $handle.
+When using EVENTLOG_SEQUENTIAL_READ, OFFSET must have the following values:
+
+=over 4
+
+=item 1
+
+Reset read from start (either first or last record depending on
+EVENTLOG_FORWARDS_READ / EVENTLOG_BACKWARDS_READ flags)
+
+=item 0
+
+Read the next item.
+
+=back
+
=item $handle->Close();
The Close() method closes the EventLog represented by $handle. After
@@ -459,13 +474,15 @@
=head1 BUGS
-None currently known.
+See L<
https://rt.cpan.org/NoAuth/Bugs.html?Dist=Win32-EventLog>
The test script for 'make test' should be re-written to use the
EventLog object.
=head1 AUTHOR
-Original code by Jesse Dougherty for HiP Communications. Additional
-fixes and updates attributed to Martin Pauley
-<martin.pauley@ulsterbank.ltd.uk>) and Bret Giddings (bret@essex.ac.uk).
+Original code by Jesse Dougherty for HiP Communications.
+
+Additional fixes and updates attributed to Martin Pauley
+<martin.pauley@ulsterbank.ltd.uk>), Bret Giddings (<bret@essex.ac.uk>)
+and Olivier MenguE<eacute> (<dolmen@cpan.org>).