Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Event Viewer 1

Status
Not open for further replies.

usadra

Programmer
Sep 14, 2001
5
IN
How to access the EVENT VIEWER from VB that is present in the Administrative tool?
 
Strongm right! It's not easy

you really need to know your API stuff

I found a VB example, can't remember where tho'

I'll look it up and post back

Matt
 
mattknight,
Does GetEventLog API does that?
 
usadra,

I am sorry, I can't find the link to the example is found
in brief you need to

Open handle to event log using OpenEventLog()
i.e
Code:
dim lHandle as long
dim lRecs as long
dim lRet as long
dim sServer as string
dim sSource as string

sSource = "Application" 'event source you are interested in
sServer = "."       'Server name . for local machine

lHandle = OpenEventLog(sServer, sSource)
'check handle is valid  i.e. > 0

' Read number of records
lRet = GetNumberofEventLogRecords(lHandle, lRecs)

'check success i.e. lRet > 0

'Read record into EVENTLOGRECORD udt
'this is the tricky bit as the record size is variable
' and you will need to improve this code SUBSTANTIALLY
'because it reads 1 record into a fixed buffer very ineffecient

dim lBytes1 as long, lBytes2 as long, lBytes3 as long
dim udtRecs as EVENTLOGRECORD
lBytes1 = 4096
lRet = ReadEventLog(lHandle, EVENTLOG_FORWARDS_READ + EVENTLOG_SEQUENTIAL_READ,0,udtRecs, lBytes1, lBytes2, lBytes3)

'that is really nasty..
' you will need to convert the times from UTC something easier to manipulate e.g.double or variant date

'You will alos need to locate the message dll, which will
'be stored in HKLM\system\currentcontrolset\services' eventlog\<source>\eventmessagefile
'
' You need to load this file using LoadLibraryEx
' and then use the formatmessageapi to convert the event id
' to the relevant string
'

I hope that this gives you a start to solve the problem.
You will need to improve that bit about reading thge event log record substantially look up MSDN!

I will try and produce a fuller (and better) solution in due course...

strongm
Oh, I've written code that does it.
perhaps you could post your solution, which I am sure will be considerably fuller and better than mine, then both Usadra and I could learn from it?

Matt

 
Sorry, my reservation in providing the code is related to trying to determine the level of knowledge of the original questionner. It really isn't straightforward. For example, most event messages are not actually held in the event log. That merely holds some pointers. You actually need to identify and load various event log message handlers (i.e your commented code) to allow them to be dereferenced into something that actually makes sense.

Additionally, my code is a proof of concept (an investigation into whether reading the event logs was feasible or not in VB), and therefore - whilst it works fine - is not the easiest code in the world to follow. And it includes a hack that I'm not really comfortable with...

Now, if you really, really want me to post it here, then fine. Just don't expect too much explanation or support.
 
strongm

Thanks for the clarification,
my major difficulty (currently at least) with this problem is allocation of memory for the EVENTLOGRECORD structure (udt). I am aware of how the eventlog uses message DLLs to reduce the log size, and can work out how to access the stored messages.

AS you can see I used a major bodge ( I won't even justify it as a hack ;-) ) to read 1 record, can you post some ideas on how to allocate the memory.

I understand the way that the ReadEventlog returns its buffer requirements,but How do I respond to them?

I can understand your reluctance to post a proof of concept solution having tried to prove the concept myself...

For me this is a relatively low priority: but it is a useful technique to use! Perhaps Usadra's needs are more pressing!

Just as an aside, do you think it worthwhile producing a FAQ on how to create a message DLL and write meaningful entries to the eventlog as the native implementation is a lttle slim?

Matt
 
As far as writing events to the logs is concerned, tend to use the LogEvent method of NTSVC.OCX.

ANyway, here's my Event Log reading code:
[tt]
Option Explicit

Private Type EVENTLOGRECORD
Length As Long ' Length of full record 0
Reserved As Long ' Used by the service 4
RecordNumber As Long ' Absolute record number 8
TimeGenerated As Long ' Seconds since 1-1-1970 12
TimeWritten As Long 'Seconds since 1-1-1970 16
EventID As Long ' 20
EventType As Integer '24
NumStrings As Integer '26
EventCategory As Integer '28
ReservedFlags As Integer ' For use with paired events (auditing) 30
ClosingRecordNumber As Long 'For use with paired events (auditing) 32
StringOffset As Long ' Offset from beginning of record 36
UserSidLength As Long '40
UserSidOffset As Long '44
DataLength As Long '48
DataOffset As Long ' Offset from beginning of record 52
End Type

Private Declare Function ReadEventLog Lib &quot;advapi32.dll&quot; Alias &quot;ReadEventLogA&quot; (ByVal hEventLog As Long, ByVal dwReadFlags As Long, ByVal dwRecordOffset As Long, ByVal lpBuffer As String, ByVal nNumberOfBytesToRead As Long, pnBytesRead As Long, pnMinNumberOfBytesNeeded As Long) As Long

Private Declare Function OpenEventLog Lib &quot;advapi32.dll&quot; Alias &quot;OpenEventLogA&quot; (ByVal lpUNCServerName As String, ByVal lpSourceName As String) As Long
Private Declare Function CloseEventLog Lib &quot;advapi32.dll&quot; (ByVal hEventLog As Long) As Long
Private Declare Function GetOldestEventLogRecord Lib &quot;advapi32.dll&quot; (ByVal hEventLog As Long, OldestRecord As Long) As Long
Private Declare Function GetNumberOfEventLogRecords Lib &quot;advapi32.dll&quot; (ByVal hEventLog As Long, NumberOfRecords As Long) As Long

Private Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long)


Private Declare Function RegOpenKey Lib &quot;advapi32.dll&quot; Alias &quot;RegOpenKeyA&quot; (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegQueryValueEx Lib &quot;advapi32.dll&quot; Alias &quot;RegQueryValueExA&quot; (ByVal hKey As Long, ByVal lpValueName As String, ByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long
Private Declare Function RegCloseKey Lib &quot;advapi32.dll&quot; (ByVal hKey As Long) As Long
Private Declare Function LoadLibraryEx Lib &quot;kernel32&quot; Alias &quot;LoadLibraryExA&quot; (ByVal lpLibFileName As String, ByVal hFile As Long, ByVal dwFlags As Long) As Long
Private Declare Function FreeLibrary Lib &quot;kernel32&quot; (ByVal hLibModule As Long) As Long
Private Declare Function FormatMessage Lib &quot;kernel32&quot; Alias &quot;FormatMessageA&quot; (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Any) As Long

'Private Declare Function GetSystemDirectory Lib &quot;kernel32&quot; Alias &quot;GetSystemDirectoryA&quot; (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Private Declare Function ExpandEnvironmentStrings Lib &quot;kernel32&quot; Alias &quot;ExpandEnvironmentStringsA&quot; (ByVal lpSrc As String, ByVal lpDst As String, ByVal nSize As Long) As Long


Public Const EVENTLOG_SECURITY = &quot;Security&quot; '&quot;Security&quot; '+ Chr$(0)
Public Const EVENTLOG_APPLICATION = &quot;Application&quot; '+ Chr$(0)
Public Const EVENTLOG_SYSTEM = &quot;System&quot; '+ Chr$(0)

Public Const EVENTLOG_SEQUENTIAL_READ = &H1
Public Const EVENTLOG_SEEK_READ = &H2
Public Const EVENTLOG_FORWARDS_READ = &H4
Public Const EVENTLOG_BACKWARDS_READ = &H8

Public Const EVENTLOG_SUCCESS = &H0
Public Const EVENTLOG_ERROR_TYPE = &H1
Public Const EVENTLOG_WARNING_TYPE = &H2
Public Const EVENTLOG_INFORMATION_TYPE = &H4
Public Const EVENTLOG_AUDIT_SUCCESS = &H8
Public Const EVENTLOG_AUDIT_FAILURE = &H10

Private Const HKEY_LOCAL_MACHINE = &H80000002
Private Const FORMAT_MESSAGE_FROM_HMODULE = &H800
Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000

Private Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
Private Const FORMAT_MESSAGE_ARGUMENT_ARRAY = &H2000

Private Const LOAD_LIBRARY_AS_DATAFILE As Long = 2&

' First hint of the hack we are going to do...
Public Type HackLog
s1 As String
s2 As String
s3 As String
s4 As String
s5 As String
s6 As String
s7 As String
s8 As String
s9 As String
s10 As String
End Type

Public Sub vbReadEventLog()
Dim hEventLog As Long
Dim lResult As Long
Dim lRecords As Long
Dim lOldestRecord As Long
Dim lReadFlags As Long
Dim myEventLogRecord As EVENTLOGRECORD
Dim strBuffer As String
Dim lBytesToRead As Long
Dim lBytesRead As Long
Dim lMinNumBytesNeeded As Long
Dim lRecordOffset As Long
Dim strSPlitter() As String

Dim lp As Long

hEventLog = OpenEventLog(&quot;&quot;, EVENTLOG_SYSTEM) ' We'll be looking at local machine

If hEventLog Then
lResult = GetOldestEventLogRecord(hEventLog, lOldestRecord)
lResult = GetNumberOfEventLogRecords(hEventLog, lRecords)
If lResult Then
lReadFlags = EVENTLOG_BACKWARDS_READ Or EVENTLOG_SEEK_READ

strBuffer = Space(1024)
lBytesToRead = 0

For lp = lOldestRecord + lRecords - 1 To lOldestRecord + lRecords - 1 - 24 Step -1 'lOldestRecord To lOldestRecord + lRecords - 1 ' Read one at a time (optimise by reading ALL)

lRecordOffset = lp

'get Bytes necessary
strBuffer = Space(0)
lBytesToRead = 0
lResult = ReadEventLog(hEventLog, lReadFlags, lRecordOffset, strBuffer, lBytesToRead, lBytesRead, lMinNumBytesNeeded)

If lResult = False Then
strBuffer = Space(lMinNumBytesNeeded)
lBytesToRead = lMinNumBytesNeeded
lResult = ReadEventLog(hEventLog, lReadFlags, lRecordOffset, strBuffer, lBytesToRead, lBytesRead, lMinNumBytesNeeded)
End If
CopyMemory myEventLogRecord, ByVal strBuffer, Len(myEventLogRecord)

'Debug.Print myEventLogRecord.EventID And &H3FFF
strSPlitter = Split(Mid(strBuffer, 57, myEventLogRecord.UserSidOffset + myEventLogRecord.UserSidLength - 58), Chr(0))
Debug.Print strSPlitter(0) 'Source
Debug.Print strSPlitter(1) 'Computer

Dim fred As String
fred = Mid(strBuffer, myEventLogRecord.StringOffset + 1, myEventLogRecord.DataOffset - myEventLogRecord.StringOffset)

Debug.Print DateAdd(&quot;s&quot;, myEventLogRecord.TimeGenerated, &quot;1/Jan/1970 00:00:00&quot;) ' Daylight savings time not included...

LocateMessage myEventLogRecord.EventID, strSPlitter(0), fred, &quot;System&quot;
Debug.Print fred
Next
End If
End If

' Clean up if we found a log file
If hEventLog Then
CloseEventLog hEventLog
End If
End Sub

Private Function LocateMessage(ByVal EventID As Long, strSource As String, strArg As String, strLog As String) As Long
Dim hKey As Long
Dim lType As Long
Dim strBuffer As String
Dim lSize As Long
Dim hModule As Long
'dim strMessage as string
Dim result As Long
Dim strArrayArg() As String
Dim strTemp As String

RegOpenKey HKEY_LOCAL_MACHINE, &quot;SYSTEM\CurrentControlSet\Services\EventLog\&quot; & strLog & &quot;\&quot; & strSource, hKey
RegQueryValueEx hKey, &quot;EventMessageFile&quot;, 0&, lType, 0, lSize
strBuffer = Space(lSize)
result = RegQueryValueEx(hKey, &quot;EventMessageFile&quot;, 0&, lType, ByVal strBuffer, lSize)

strTemp = &quot;&quot; 'Space(1024)
result = 0
result = ExpandEnvironmentStrings(strBuffer, strTemp, 0)
strTemp = Space(result)
ExpandEnvironmentStrings strBuffer, strTemp, result
strBuffer = strTemp

hModule = LoadLibraryEx(strBuffer, 0&, LOAD_LIBRARY_AS_DATAFILE)
strArrayArg = Split(strArg, Chr(0))



Dim fred As HackLog


' Here comes the hack...
fred = ArrayToUDT(strArrayArg())

strBuffer = Space(1023)

result = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE Or FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_ARGUMENT_ARRAY, ByVal hModule, EventID, 0&, strBuffer, Len(strBuffer), fred) 'Or FORMAT_MESSAGE_IGNORE_INSERTS
'Beep
FreeLibrary hModule
If result Then strArg = Left(strBuffer, result)
LocateMessage = True 'Left(strBuffer, result)
End Function

' From a technique illustrated by Karl E Peterson
Private Function ArrayToUDT(strArray() As String) As HackLog
Dim fred As HackLog
Dim lp As Long

For lp = LBound(strArray) To UBound(strArray)
Select Case lp
Case 0: fred.s1 = strArray(lp)
Case 1: fred.s2 = strArray(lp)
Case 2: fred.s3 = strArray(lp)
Case 3: fred.s4 = strArray(lp)
Case 4: fred.s5 = strArray(lp)
Case 5: fred.s6 = strArray(lp)
Case 6: fred.s7 = strArray(lp)
Case 7: fred.s8 = strArray(lp)
Case 8: fred.s9 = strArray(lp)
Case 9: fred.s10 = strArray(lp)
End Select
Next

ArrayToUDT = fred
End Function
 
strongm

Sorry still chewing... looked at it a little most of it I understand and can follow, the hack I'haven't got to get. Busy re-writing to pass all EVENTLOGRECORDS into collection and manipulate from there...

Had lots of other stuff to do (like trying to find new job got fired / resigned today)

will post back soon..
 
>got fired / resigned today

As we in England say: &quot;Bugger!&quot;
 
>will post back soon..

Ho hum, a little delay! but finally, I can confirm I have a solution all packed up in a com object...

Thanks very much for the start though...
Take Care

Matt
If at first you don't succeed, skydiving is not for you.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top