×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Anyone used VFP to read the windows event log?

Anyone used VFP to read the windows event log?

Anyone used VFP to read the windows event log?

(OP)
I am looking at reading the event log to look for possible 'probes' and update the firewall rules automatically

Anyone done this already?

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

(OP)
Thank you Gerrit

I found this article https://github.com/VFPX/Win32API/blob/master/sampl...

It ought to be possible to read the log from within VFP, without exporting the logs... but if I can't
get my head round it... happy shades

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

For starters, Griff:

CODE

o = CreateObject("WindowsEventLog",".","Application")
? o.GetNumberOfRecords() 
Displays some ten thousands for me, and trying to read the log (this class only reads a full log or nothing) takes a looong time.
But I don't think this is intended to read one of the standard logs, but one you make yourself, for your own application.

Chriss

RE: Anyone used VFP to read the windows event log?

(OP)
Hi Chriss

The link I found actually works, albeit it is hardly the two line answer you've given!

It is a slow process though.

I claim no ownership or authorship of the code below, 99.99% taken from the github link
above and dropped into a single .prg

CODE

#DEFINE EVENTLOG_SEQUENTIAL_READ 1
#DEFINE EVENTLOG_FORWARDS_READ 4
#DEFINE ERROR_INSUFFICIENT_BUFFER 122
#DEFINE WE_START_DATETIME {^1970/01/01 00:00:00}
#DEFINE ERROR_HANDLE_EOF 38
#DEFINE EVENTLOGRECORD_SIZE 56
#DEFINE MAX_BUFFER_SIZE 0x7ffff
#DEFINE EVENTLOG_FULL_INFO 0
#DEFINE FACILITY_NULL 0

LOCAL welog As WindowsEventLog,;  
	werecord As WindowsEventRecord, nReccount  

  
welog = CREATEOBJECT("WindowsEventLog",;  
	NULL, "Security")  
  
WAIT WINDOW NOWAIT "Reading log records..."  
nReccount = welog.ReadLogRecords()  
WAIT CLEAR  
  
CREATE CURSOR csResult ( recordnumber I,;  
	timegenerated T, timewritten T,;  
	eventid I, eventtype I, numstrings I,;  
	eventcategory I, stringoffset I,;  
	datalength I, dataoffset I, strings M,;  
	eventdata M, eventbuffer M,;  
	sysname C(32), source C(200))  
  
FOR EACH werecord IN welog.WindowEventRecords  
	WITH werecord  
		INSERT INTO csResult VALUES (.recordnumber,;  
			WE_START_DATETIME+.timegenerated,;  
			WE_START_DATETIME+.timewritten,;  
			.eventid, .eventtype, .numstrings,;  
			.eventcategory, .stringoffset,;  
			.datalength, .dataoffset,;  
			.strings, .eventdata, .eventbuffer,;  
			.sysname, .source)  
	ENDWITH  
NEXT

SELECT csResult
GO TOP
BROWSE
QUIT


DEFINE CLASS WindowsEventLog As Session
PROTECTED servername, logname, hEventLog
	WindowEventRecords=NULL
	servername=NULL
	logname=NULL
	hEventLog=0
	errorno=0
	errormessage=""

PROCEDURE Init(cServerName As String, cLogName As String)
	THIS.declare
	THIS.logname = m.cLogName
	THIS.servername = m.cServerName
	THIS.WindowEventRecords = CREATEOBJECT("Collection")

PROCEDURE Destroy
	THIS.CloseLog

PROCEDURE ResetError
	THIS.SetError(0, "")

PROCEDURE SetError(nErrorNo, cErrorMessage)
	THIS.errorno=m.nErrorNo
	THIS.errormessage=m.cErrorMessage

FUNCTION GetNumberOfRecords() As Number
	IF NOT THIS.OpenLog()
		RETURN -1
	ENDIF

	LOCAL nRecno, nResult
	nRecno=0
	
	nResult = GetNumberOfEventLogRecords(;
		THIS.hEventLog, @nRecno)

	IF nResult = 0
		THIS.SetError(GetLastError(),;
			"Call to GetNumberOfEventLogRecords() failed.")
		nRecno = -1
	ENDIF

	THIS.CloseLog
RETURN m.nRecno

FUNCTION IsLogFull() As Boolean
* indicates whether the event log is full
	LOCAL nResult, nLogFull, nBufsize
	STORE 0 TO nLogFull, nBufsize

	IF NOT THIS.OpenLog()
		RETURN .F.
	ENDIF

	nResult = GetEventLogInformation(THIS.hEventLog,;
		EVENTLOG_FULL_INFO, @nLogFull, 4, @nBufsize)

	IF nResult = 0
		THIS.SetError(GetLastError(),;
			"Call to GetEventLogInformation() failed.")
	ENDIF
	THIS.CloseLog
RETURN (m.nLogFull <> 0)

FUNCTION ClearLog(cBackupFile As String) As Boolean
	IF NOT THIS.OpenLog()
		RETURN .F.
	ENDIF

	IF EMPTY(m.cBackupFile)
		cBackupFile=NULL
	ENDIF
	
	LOCAL nResult, nError
	nResult = ClearEventLog(THIS.hEventLog, m.cBackupFile)

	IF m.nResult = 0
		THIS.SetError(GetLastError(),;
			"Call to ClearEventLog() failed.")
	ENDIF
	THIS.CloseLog
RETURN (m.nResult <> 0)

PROCEDURE ReadLogRecords
	DO WHILE THIS.WindowEventRecords.Count > 0
		THIS.WindowEventRecords.Remove(1)
	ENDDO
	
	THIS.CloseLog
	THIS.hEventLog = OpenEventLog(THIS.servername, THIS.logname)

	IF THIS.hEventLog = 0
		THIS.SetError(GetLastError(), "Call to OpenEventLog() failed.")
		RETURN 0
	ENDIF

	LOCAL nRecno, nReccount, nIndex, oBuffer As PChar, nBufsize,;
		nBytesRead, hBuffer, nBytesNeeded, nResult, nLastError,;
		nReadCount

	STORE 0 TO nRecno, nReccount
	= GetOldestEventLogRecord(THIS.hEventLog, @nRecno)
	= GetNumberOfEventLogRecords(THIS.hEventLog, @nReccount)

	nBufsize = MAX_BUFFER_SIZE
	oBuffer = CREATEOBJECT("PChar", REPLICATE(CHR(0), nBufsize))

	DO WHILE .T.
		oBuffer.SetValue(REPLICATE(CHR(0), nBufsize))
		hBuffer = oBuffer.GetAddr()
		STORE 0 TO nBytesRead, nBytesNeeded

		nResult = ReadEventLog(THIS.hEventLog,;
			BITOR(EVENTLOG_SEQUENTIAL_READ, EVENTLOG_FORWARDS_READ), 0,;
			m.hBuffer, nBufsize, @nBytesRead, @nBytesNeeded)

		IF nResult <> 0
			THIS.ProcessBuffer(@oBuffer, m.nBytesRead)
			LOOP
		ENDIF

		nLastError = GetLastError()
		DO CASE
		CASE nLastError = ERROR_HANDLE_EOF
			EXIT
		OTHERWISE
			THIS.SetError(m.nLastError, "ReadEventLog call failed.")
			EXIT
		ENDCASE
	ENDDO

	THIS.CloseLog
RETURN THIS.WindowEventRecords.Count

PROTECTED PROCEDURE ProcessBuffer(oBuffer As PChar, nBytesRead As Number)
	LOCAL hBuffer, cMBuffer, cBuffer, nOffset, nRecordLength,;
		werecord As WindowsEventRecord, cStrings

	hBuffer = oBuffer.GetAddr()
	cMBuffer = SUBSTR(oBuffer.GetValue(), 1, m.nBytesRead)
	nOffset=1

	DO WHILE .T.
		nRecordLength = buf2dword(SUBSTR(m.cMBuffer, nOffset, 4))
		cBuffer = SUBSTR(m.cMBuffer, nOffset, nRecordLength)

		werecord = CREATEOBJECT("WindowsEventRecord")
		WITH werecord
			.eventbuffer = m.cBuffer
			.recordnumber = buf2dword(SUBSTR(cBuffer, 9,4))
			.timegenerated = buf2dword(SUBSTR(cBuffer, 13,4))
			.timewritten = buf2dword(SUBSTR(cBuffer, 17,4))
			.eventid = buf2dword(SUBSTR(cBuffer, 21,4))
			.eventtype = buf2word(SUBSTR(cBuffer, 25,2))
			.numstrings = buf2word(SUBSTR(cBuffer, 27,2))
			.eventcategory = buf2word(SUBSTR(cBuffer, 29,2))
			.stringoffset = buf2dword(SUBSTR(cBuffer, 37,4))
			.datalength = buf2dword(SUBSTR(cBuffer, 49,4))
			.dataoffset = buf2dword(SUBSTR(cBuffer, 53,4))
			
			IF .numstrings > 0
				cStrings = SUBSTR(cBuffer, .stringoffset+1)
				.strings = SUBSTR(cStrings, 1,;
					AT(CHR(0), cStrings, .numstrings))
			ENDIF
			
			IF .datalength > 0
				.eventdata = SUBSTR(cBuffer, .dataoffset+1, .datalength)
			ENDIF
			
			cStrings = SUBSTR(cBuffer, EVENTLOGRECORD_SIZE+1)
			.source = SUBSTR(cStrings, 1, AT(CHR(0), cStrings)-1)
			.sysname = SUBSTR(cStrings, AT(CHR(0), cStrings)+1)
			.sysname = SUBSTR(.sysname, 1, AT(CHR(0), .sysname)-1)
		ENDWITH

		THIS.WindowEventRecords.Add(werecord)
		werecord=NULL

		nOffset = m.nOffset + m.nRecordLength
		IF nOffset > LEN(m.cMBuffer) - EVENTLOGRECORD_SIZE
			EXIT
		ENDIF
	ENDDO

PROTECTED FUNCTION OpenLog() As Boolean
	IF THIS.hEventLog = 0
		THIS.hEventLog = OpenEventLog(;
			THIS.servername, THIS.logname)
	ENDIF
RETURN (THIS.hEventLog <> 0)

PROTECTED PROCEDURE CloseLog
	IF THIS.hEventLog <> 0
		= CloseEventLog(THIS.hEventLog)
		THIS.hEventLog = 0
	ENDIF

PROTECTED PROCEDURE declare
	DECLARE INTEGER GetLastError IN kernel32
	DECLARE INTEGER CloseEventLog IN advapi32 INTEGER hEventLog

	DECLARE INTEGER OpenEventLog IN advapi32;
		STRING lpUNCServerName, STRING lpSourceName

	DECLARE INTEGER GetOldestEventLogRecord IN advapi32;
		INTEGER hEventLog, LONG @OldestRecord

	DECLARE INTEGER GetNumberOfEventLogRecords IN advapi32;
		INTEGER hEventLog, LONG @NumberOfRecords

	DECLARE INTEGER ReadEventLog IN advapi32;
		INTEGER hEventLog, LONG dwReadFlags, LONG dwRecordOffset,;
		INTEGER lpBuffer, LONG nNumberOfBytesToRead,;
		LONG @pnBytesRead, LONG @pnMinNumberOfBytesNeeded

	DECLARE INTEGER ClearEventLog IN advapi32;
		INTEGER hEventLog, STRING lpBackupFileName

	DECLARE INTEGER GetEventLogInformation IN advapi32;
		INTEGER hEventLog, LONG dwInfoLevel, LONG @lpBuffer,;
		LONG cbBufSize, LONG @pcbBytesNeeded

ENDDEFINE

DEFINE CLASS WindowsEventRecord As Session
	eventbuffer=""
	recordnumber=0
	timegenerated=0
	timewritten=0
	eventid=0
	eventtype=0
	numstrings=0
	eventcategory=0
	stringoffset=0
	datalength=0
	dataoffset=0
	strings=""
	eventdata=""
	source=""
	sysname=""

FUNCTION GetString(nIndex As Number) As String
* returns a string from event record data
* specified by string index
	IF THIS.numstrings < nIndex
		RETURN ""
	ENDIF

	LOCAL nPosStart, nPosEnd
	nPosEnd = AT(CHR(0), THIS.strings, nIndex)
	nPosStart = IIF(m.nIndex=1, 1, AT(CHR(0), THIS.strings, nIndex-1)+1)
RETURN SUBSTR(THIS.strings, nPosStart, nPosEnd-nPosStart)

FUNCTION UtcSecondsToDateTime(nSeconds As Number) As Datetime
RETURN WE_START_DATETIME + m.nSeconds

ENDDEFINE

DEFINE CLASS PChar As Session  && pointer to string
PROTECTED hMem

PROCEDURE Init(lcString)
	THIS.hMem = 0
	THIS.setValue(lcString)

PROCEDURE Destroy
	THIS.ReleaseString

FUNCTION GetAddr
RETURN THIS.hMem

FUNCTION GetValue
	LOCAL lnSize, lcBuffer
	lnSize = THIS.getAllocSize()
	lcBuffer = SPACE(lnSize)

	IF THIS.hMem <> 0
		DECLARE RtlMoveMemory IN kernel32 As MemToStr;
			STRING @, INTEGER, INTEGER
		= MemToStr(@lcBuffer, THIS.hMem, lnSize)
	ENDIF
RETURN lcBuffer

FUNCTION GetAllocSize
	DECLARE INTEGER GlobalSize IN kernel32 INTEGER hMem
RETURN Iif(THIS.hMem=0, 0, GlobalSize(THIS.hMem))

PROCEDURE SetValue(lcString)
#DEFINE GMEM_FIXED 0
	THIS.ReleaseString

	DECLARE INTEGER GlobalAlloc IN kernel32 INTEGER, INTEGER
	DECLARE RtlMoveMemory IN kernel32 As StrToMem;
		INTEGER, STRING @, INTEGER

	LOCAL lnSize
	lcString = lcString + Chr(0)
	lnSize = Len(lcString)
	THIS.hMem = GlobalAlloc(GMEM_FIXED, lnSize)
	IF THIS.hMem <> 0
		= StrToMem(THIS.hMem, @lcString, lnSize)
	ENDIF

PROCEDURE ReleaseString
	IF THIS.hMem <> 0
		DECLARE INTEGER GlobalFree IN kernel32 INTEGER
		= GlobalFree (THIS.hMem)
		THIS.hMem = 0
	ENDIF
ENDDEFINE

FUNCTION buf2dword(cBuffer)
RETURN Asc(SUBSTR(cBuffer, 1,1)) + ;
	BitLShift(Asc(SUBSTR(cBuffer, 2,1)),  8) +;
	BitLShift(Asc(SUBSTR(cBuffer, 3,1)), 16) +;
	BitLShift(Asc(SUBSTR(cBuffer, 4,1)), 24)

FUNCTION buf2word(lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ;
       Asc(SUBSTR(lcBuffer, 2,1)) * 256 

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

Griff,

it is really beyond me, how you cannot see this.

my usage exameple is using the class definition you liknked to. Yes, OF COURSE, you have to first establish this whole class from the link you've given.

Here's how the code starts, Griff:

CODE -->

#DEFINE EVENTLOG_SEQUENTIAL_READ 1
...some more constatn definitions
DEFINE CLASS WindowsEventLog As Session
PROTECTED servername, logname, hEventLog
... 

And there is no usage example, it's just a class definition. What do you do with a class, Griff? You do a CREATEOBJECT, and then you call methods.

My short code needs this class definition, it's just the usage example, Griff, but it's all you need additionally to the class definiiotn. Is that clearer, now?

Chriss

RE: Anyone used VFP to read the windows event log?

(OP)
Chris

I did not realise your example was using the class in the link...


Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

Griff,

my code:

CODE

o = CreateObject("WindowsEventLog",... 

class definition:

CODE

DEFINE CLASS WindowsEventLog As Session 

Do I really need to point out my few lines need this class definition?

Chriss

RE: Anyone used VFP to read the windows event log?

(OP)
In this case you did!
I hadn't even read the class definition when I posted my link!

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

It's possibly somewhat easier with WMI ...

RE: Anyone used VFP to read the windows event log?

(OP)
@Strongm

I'll take a look

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

Indeed, that you can use "." as servername for the local computer is a strong hint WMI is involved anyway. With WMI you should be able to do an actual query from a log, too, which gives a higher flexibility about which entries you want to read.

Chriss

RE: Anyone used VFP to read the windows event log?

(OP)
I did not find that, I did search for Windows Event Log, but I didn't find that, thank you... trouble with searches, sometimes you need to know the answer
to phrase the question!


Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

RE: Anyone used VFP to read the windows event log?

And Griff,

here's an adaption of the query, if you only want to read errors that were logged since November 2022, it's not standalone code, it's what you change in Mike Gagnons code:

CODE -->

...Mike Gagnons code..
colLoggedEvents = loWMIService.ExecQuery ;
    ("Select * from Win32_NTLogEvent Where Logfile = 'Application' and TimeWritten>='20221101' and Type='Error'")
...Mike Gagnons code... 

Notice the terms for a Win32_NTLogEvent.Type are locale specific, for example 'Erreur' instead of 'Error' in French.

Chriss

RE: Anyone used VFP to read the windows event log?

Griff, if you search for [Windows Event Log] that highlights "Windows" "Event" and "Log" in the results. If you want to search for Windows Event Logs, search for "Windows Event Logs"...

Chriss

RE: Anyone used VFP to read the windows event log?

(OP)
Thanks Chriss... just like the google search happy shades

Regards

Griff
Keep Smileing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close