Sunblood Posted July 28, 2020 Share Posted July 28, 2020 Using EventLog__Read() to search recent logs for Application Error events. After finding one and parsing the info, the [13] value in the returned array does not properly contain the application name or version; instead it reads %1 and %2. Here's a side-by-side of the actual event log and a message box of $array[13] as returned by EventLog__Read() Script: #include <EventLog.au3> #include <Array.au3> $hEventLog = _EventLog__Open("", "Application") While 1 $m = _EventLog__Read($hEventLog, True, False) If IsArray($m) Then If $m[10] = "Application error" Then MsgBox(0,"",$m[13]) EndIf EndIf WEnd _EventLog__Close($hEventLog) Link to comment Share on other sites More sharing options...
argumentum Posted July 28, 2020 Share Posted July 28, 2020 (edited) 1 hour ago, Sunblood said: the [13] value in the returned array does not properly contain the application name or version [13] = Event description And yes, I see that it does what you claim Edit: solution in the next post Edited July 29, 2020 by argumentum =) Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
argumentum Posted July 29, 2020 Share Posted July 29, 2020 (edited) ..solution is to change/fix __EventLog_DecodeDesc(), but here is a hack for now: expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Version=Beta #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <EventLog.au3> #include <FontConstants.au3> #include <GUIConstantsEx.au3> Global $g_idMemo = 0, $g_StrMemo = "" Example() Func Example() Local $hEventLog, $aEvent ; Create GUI GUICreate("EventLog [ x64 = " & Not Not @AutoItX64 & " ][ AutoIt = v" & @AutoItVersion & " ]", 800, 400) $g_idMemo = GUICtrlCreateEdit("", 0, 0, 800, 400, 0) GUICtrlSetFont($g_idMemo, 9, $FW_NORMAL, $GUI_FONTNORMAL, "Courier New") GUISetState(@SW_SHOW) ; Read most current event record $hEventLog = _EventLog__Open("", "Application") Do $aEvent = _EventLog__Read2($hEventLog, True, False) ; read last event GUICtrlSetData($g_idMemo, @CRLF & @CRLF & @CRLF & @TAB & $aEvent[1] & @CRLF & @TAB & $aEvent[2] & " " & $aEvent[3]) If GUIGetMsg() = $GUI_EVENT_CLOSE Or $aEvent[0] = False Then _EventLog__Close($hEventLog) GUIDelete() Exit 3 EndIf Until StringInStr($aEvent[10], "Application error") MemoWrite("Result ............: " & $aEvent[0]) MemoWrite("Record number .....: " & $aEvent[1]) MemoWrite("Submitted .........: " & $aEvent[2] & " " & $aEvent[3]) MemoWrite("Generated .........: " & $aEvent[4] & " " & $aEvent[5]) MemoWrite("Event ID ..........: " & $aEvent[6]) MemoWrite("Type ..............: " & $aEvent[8]) MemoWrite("Category ..........: " & $aEvent[9]) MemoWrite("Source ............: " & $aEvent[10]) MemoWrite("Computer ..........: " & $aEvent[11]) MemoWrite("Username ..........: " & $aEvent[12]) MemoWrite("Description .......: " & $aEvent[13]) MemoWrite() _EventLog__Close($hEventLog) ; Loop until the user exits. Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete() EndFunc ;==>Example ; Write a line to the memo control Func MemoWrite($sMessage = Default) If $sMessage = Default Then Return GUICtrlSetData($g_idMemo, $g_StrMemo) $g_StrMemo &= $sMessage & @CRLF EndFunc ;==>MemoWrite Func _EventLog__Read2($hEventLog, $fRead = True, $fForward = True, $iOffset = 0) ; https://www.autoitscript.com/forum/topic/203482-eventlog__read-returning-1-2-instead-of-application-name/?do=findComment&comment=1461138 Local $iReadFlags, $aEvent[15] $aEvent[0] = False ; in cas of error If $fRead Then $iReadFlags = $EVENTLOG_SEQUENTIAL_READ Else $iReadFlags = $EVENTLOG_SEEK_READ EndIf If $fForward Then $iReadFlags = BitOR($iReadFlags, $EVENTLOG_FORWARDS_READ) Else $iReadFlags = BitOR($iReadFlags, $EVENTLOG_BACKWARDS_READ) EndIf ; First call gets the size for the buffer. A fake buffer is passed because ; the function demands the buffer be non-NULL even when requesting the size. Local $tBuffer = DllStructCreate("wchar[1]") Local $aResult = DllCall("advapi32.dll", "bool", "ReadEventLogW", "handle", $hEventLog, "dword", $iReadFlags, "dword", $iOffset, _ "struct*", $tBuffer, "dword", 0, "dword*", 0, "dword*", 0) If @error Then Return SetError(@error, @extended, $aEvent) ; Allocate the buffer and repeat the call obtaining the information. Local $iBytesMin = $aResult[7] $tBuffer = DllStructCreate("wchar[" & $iBytesMin + 1 & "]") $aResult = DllCall("advapi32.dll", "bool", "ReadEventLogW", "handle", $hEventLog, "dword", $iReadFlags, "dword", $iOffset, _ "struct*", $tBuffer, "dword", $iBytesMin, "dword*", 0, "dword*", 0) If @error Or Not $aResult[0] Then Return SetError(@error, @extended, $aEvent) Local $tEventLog = DllStructCreate($tagEVENTLOGRECORD, DllStructGetPtr($tBuffer)) $aEvent[0] = True $aEvent[1] = DllStructGetData($tEventLog, "RecordNumber") $aEvent[2] = __EventLog_DecodeDate(DllStructGetData($tEventLog, "TimeGenerated")) $aEvent[3] = __EventLog_DecodeTime(DllStructGetData($tEventLog, "TimeGenerated")) $aEvent[4] = __EventLog_DecodeDate(DllStructGetData($tEventLog, "TimeWritten")) $aEvent[5] = __EventLog_DecodeTime(DllStructGetData($tEventLog, "TimeWritten")) $aEvent[6] = __EventLog_DecodeEventID($tEventLog) $aEvent[7] = DllStructGetData($tEventLog, "EventType") $aEvent[8] = __EventLog_DecodeTypeStr(DllStructGetData($tEventLog, "EventType")) $aEvent[9] = __EventLog_DecodeCategory($tEventLog) $aEvent[10] = __EventLog_DecodeSource($tEventLog) $aEvent[11] = __EventLog_DecodeComputer($tEventLog) $aEvent[12] = __EventLog_DecodeUserName($tEventLog) $aEvent[13] = __EventLog_DecodeDesc_3($tEventLog) ; <--- the offending function $aEvent[14] = __EventLog_DecodeData($tEventLog) Return $aEvent EndFunc ;==>_EventLog__Read2 Func __EventLog_DecodeDesc_3($tEventLog) ; https://www.autoitscript.com/forum/topic/203482-eventlog__read-returning-1-2-instead-of-application-name/?do=findComment&comment=1461138 Local $aStrings = __EventLog_DecodeStrings($tEventLog) Local $sSource = __EventLog_DecodeSource($tEventLog) Local $iEventID = DllStructGetData($tEventLog, "EventID") Local $sKey = "HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\" & $__g_sSourceName_Event & "\" & $sSource Local $aMsgDLL = StringSplit(_WinAPI_ExpandEnvironmentStrings(RegRead($sKey, "EventMessageFile")), ";") Local Const $__EVENTLOG_LOAD_LIBRARY_AS_DATAFILE = 2 ; ..is a global but you may need it while testing Local Const $__EVENTLOG_FORMAT_MESSAGE_IGNORE_INSERTS = 512 ; ..is a global but you may need it while testing Local Const $__EVENTLOG_FORMAT_MESSAGE_FROM_HMODULE = 2048 ; ..is a global but you may need it while testing Local $iFlags = BitOR($__EVENTLOG_FORMAT_MESSAGE_FROM_HMODULE, $__EVENTLOG_FORMAT_MESSAGE_IGNORE_INSERTS) Local $sDesc = "" Local $tBuffer = 0 For $iI = 1 To $aMsgDLL[0] Local $hDLL = _WinAPI_LoadLibraryEx($aMsgDLL[$iI], $__EVENTLOG_LOAD_LIBRARY_AS_DATAFILE) If $hDLL = 0 Then ContinueLoop $tBuffer = DllStructCreate("wchar Text[4096]") _WinAPI_FormatMessage($iFlags, $hDLL, $iEventID, 0, $tBuffer, 4096, 0) _WinAPI_FreeLibrary($hDLL) $sDesc &= DllStructGetData($tBuffer, "Text") Next $sKey = "HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\" & $__g_sSourceName_Event & "\" & $__g_sSourceName_Event $aMsgDLL = StringSplit(_WinAPI_ExpandEnvironmentStrings(RegRead($sKey, "ParameterMessageFile")), ";") For $iI = 1 To $aMsgDLL[0] $hDLL = _WinAPI_LoadLibraryEx($aMsgDLL[$iI], $__EVENTLOG_LOAD_LIBRARY_AS_DATAFILE) If $hDLL <> 0 Then For $iJ = 1 To $aStrings[0] ;Added to parse secondary replacements $tBuffer = DllStructCreate("wchar Text[4096]") If StringLeft($aStrings[$iJ], 2) == "%%" Then _WinAPI_FormatMessage($iFlags, $hDLL, Int(StringTrimLeft($aStrings[$iJ], 2)), 0, $tBuffer, 4096, 0) If Not @error Then $aStrings[$iJ] = DllStructGetData($tBuffer, "Text") EndIf EndIf Next _WinAPI_FreeLibrary($hDLL) EndIf Next If $sDesc = "" Then For $iI = 1 To $aStrings[0] $sDesc &= $aStrings[$iI] Next Else For $iI = $aStrings[0] To 1 Step -1 ; this here needs fixing ;~ $sDesc = StringRegExpReplace($sDesc, ("(%" & $iI & ")(\R|\Z)"), StringReplace($aStrings[$iI], "\", "\\") & "$2") $sDesc = StringReplace($sDesc, "%" & $iI, $aStrings[$iI]) Next EndIf Return StringStripWS($sDesc, $STR_STRIPLEADING + $STR_STRIPTRAILING) EndFunc ;==>__EventLog_DecodeDesc_3 Edited July 30, 2020 by argumentum =) Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now