Trong Posted yesterday at 01:37 PM Posted yesterday at 01:37 PM (edited) Debug-console version of AutoIt3.exe and AutoIt3_x64.exe? I want to test my script (it already passes Au3Check.exe) by running it through CMD, and I want any errors (crashes, syntax errors, array index issues, invalid assignments, etc.) to be printed directly to the console instead of stopping the program and showing an error message box. Those pop-up error dialogs make debugging difficult because I have to switch back to SciTE every time. What I’m asking for is a console-mode debug version of AutoIt3.exe/AutoIt3_x64.exe that, when an error occurs, prints the error to the console and exits immediately with a non-zero exit code. And with compiled scripts too, is it possible to print a message on console instead of showing it? Edited yesterday at 01:41 PM by Trong DonChunior 1 Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
argumentum Posted yesterday at 03:24 PM Posted yesterday at 03:24 PM SciTE don't get those popups. They run with "/ErrorStdOut." Then you also have Opt("SetExitCode",1) 1 = Set @exitCode on Fatal error - see Exitcodes. If that is not enough then, let me know. P.S.: I really like the open source code you're integrating. Like really really like it. Thanks for that 💯 WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
argumentum Posted yesterday at 03:29 PM Posted yesterday at 03:29 PM I wrote an example some time ago too ( https://www.autoitscript.com/forum/topic/209902-optsetexitcode01 ) Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
argumentum Posted yesterday at 04:24 PM Posted yesterday at 04:24 PM #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=Icons\au3script_v9.ico #AutoIt3Wrapper_Outfile=Autoit3cui.exe #AutoIt3Wrapper_Outfile_x64=AutoIt3_x64cui.exe #AutoIt3Wrapper_Compile_Both=y #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Change2CUI=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.16.1 Author: myName #ce ---------------------------------------------------------------------------- ; Script Start - Add your code below here FileChangeDir(@ScriptDir) ; my AutoIt is installed there Opt("TrayAutoPause", 0) ; Script pauses when click on tray icon = OFF/0 Opt("TrayOnEventMode", 0) ; Enable/disable OnEvent functions notifications for the tray = OFF/0 Opt("GUICloseOnESC", 1) ; When ESC is pressed on a GUI the $GUI_EVENT_CLOSE message is sent = ON/1 #pragma compile(Console, True) #pragma compile(AutoItExecuteAllowed, True) ..also used the above and instead of running a script with AutoIt3.exe, I would run it with Autoit3cui.exe If these cui versions are in the same folder as AutoIt3.exe, all will be running just fine. Trong 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Trong Posted 11 hours ago Author Posted 11 hours ago It seems not to be the optimal solution. Even running with /ErrorStdOut still does not show the error on the console, only when running with SCITE !! Does anyone know how to use this command? /ErrorStdOut Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
water Posted 9 hours ago Posted 9 hours ago (edited) I had a similar problem a long time ago. A server application started my script. In rare cases, the script crashed due to faulty data. Trancexx helped me with this code. Edited 8 hours ago by water Trong 1 My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.0) - Download - General Help & Support - Example Scripts - Wiki ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki Task Scheduler (2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki Standard UDFs: Excel - Example Scripts - Wiki Word - Wiki Tutorials: ADO - Wiki WebDriver - Wiki
Developers Jos Posted 8 hours ago Developers Posted 8 hours ago Or make a simply RunConsole.au3 script and compile it: expandcollapse popup#AutoIt3Wrapper_Change2CUI=y $pgm = '"C:\Program Files (x86)\AutoIt3\AutoIt3.exe" /ErrorStdOut "' & $CMDLineRAW & '"' _RunCMDPgm($pgm) Func _RunCMDPgm($pgm) Local $pid $pid = Run($pgm, '', @SW_HIDE, 1 + 2 + 4) Local $handle = _ProcessExitCode($pid) ShowStdOutErr($pid) Local $exitcode = _ProcessExitCode($pid, $handle) _ProcessCloseHandle($handle) ConsoleWrite("+ Ended rc:" & $exitcode & @LF) SetError($exitcode) EndFunc ;==>_RunCMDPgm ; Func _ProcessExitCode($i_Pid, $h_Process = 0) ; 0 = Return Process Handle of PID else use Handle to Return Exitcode of a PID Local $v_Placeholder If Not IsArray($h_Process) Then ; Return the process handle of a PID $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid) If Not @error Then Return $h_Process Else ; Return Process Exitcode of PID $h_Process = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', $v_Placeholder) If Not @error Then Return $h_Process[2] EndIf Return 0 EndFunc ;==>_ProcessExitCode ; Func _ProcessCloseHandle($h_Process) ; Close the process handle of a PID DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process) If Not @error Then Return 1 Return 0 EndFunc ;==>_ProcessCloseHandle ; Func ShowStdOutErr($l_Handle) Local $Line, $tot_out, $err1 = 0, $err2 = 0 Do Sleep(10) $Line = StdoutRead($l_Handle) $err1 = @error ConsoleWrite($Line) $Lineerr = StderrRead($l_Handle) $err2 = @error ConsoleWrite($Lineerr) Until $err1 And $err2 Return EndFunc ;==>ShowStdOutErr Then run the script from the console with this compiled program: C:\test>RunConsole.exe "C:\test\test.au3" $CMDLineRAW=/ErrorStdOut ""C:\test\test.au3"" "C:\test\test.au3" (6) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.: $x [10] = 9 ^ ERROR + Ended rc:1 .. and bob's your uncle. 😉 SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past.
genius257 Posted 7 hours ago Posted 7 hours ago (edited) Hi @Trong. The issue is the way AutoIt3.exe does outputs from it's runtime My suggestion is based on this: https://stackoverflow.com/a/54252275 "D:\Downloads\autoit-v3.3.16.1\install\AutoIt3.exe" /ErrorStdOut "D:\Downloads\autoit-v3.3.16.1\install\test.au3" 2>&1|more this was my test script: ConsoleWrite("ConsoleWriteTest"&@crlf) Local $x[1] $x[10] = 9 MsgBox(0, "aya", "yay") and here is the result: Edited 7 hours ago by genius257 Trong 1 To show your appreciation My highlighted topics: AutoIt Package Manager, AutoItObject Pure AutoIt, AutoIt extension for Visual Studio Code Github: AutoIt HTTP Server, AutoIt HTML Parser
Trong Posted 4 hours ago Author Posted 4 hours ago AutoIt3cui: expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=C:\Program Files (x86)\AutoIt3\Icons\MyAutoIt3_Blue.ico #AutoIt3Wrapper_Outfile=AutoIt3cui.exe #AutoIt3Wrapper_Outfile_x64=AutoIt3cui_x64.exe #AutoIt3Wrapper_Compile_Both=y #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Change2CUI=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Configuration ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Opt("TrayAutoPause", 0) Opt("GUICloseOnESC", 0) Global Const $STR_STRIPLEADING = 1 Global Const $STR_STRIPTRAILING = 2 Global Const $PROCESS_QUERY_INFORMATION = 0x0400 Global Const $PAGE_READWRITE = 0x04 ; Hook MessageBox if compiled If @Compiled Then _AddHookApi("user32.dll", "MessageBoxW", "_Intercept_MessageBoxW", "int", "hwnd;wstr;wstr;uint") ; Main execution Global $sAutoItPath = _GetAutoItPath() Global $sCMDLineRAW = _CleanCommandLine($CMDLineRAW) Global $iTimeInit = TimerInit() ; Exit early if no arguments If StringStripWS($sCMDLineRAW, 7) == '' Then ConsoleWrite('! The process will quit immediately since no command-line arguments are present.' & @CRLF) Exit 0 EndIf ; Log execution ConsoleWrite(StringFormat("+ [%02d:%02d:%02d] %s CMDLine: %s%s", @HOUR, @MIN, @SEC, @ScriptName, $sCMDLineRAW, @CRLF)) ; Build and execute command ;~ Global $sCommand = '"' & $sAutoItPath & '" /ErrorStdOut ' & $sCMDLineRAW & ' 2>&1|more' Global $sCommand = '"' & $sAutoItPath & '" /ErrorStdOut ' & $sCMDLineRAW & '' Exit _ExecuteCommand($sCommand) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Core Functions - Optimized ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Func _CleanCommandLine($sCmd) ; Remove common AutoIt paths and flags using array for efficiency Local $aRemove[] = [ _ '"C:\Program Files (x86)\AutoIt3\AutoIt3.exe"', _ '"C:\Program Files (x86)\AutoIt3\SciTE\..\AutoIt3.exe"', _ '"C:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe"', _ '"C:\Program Files (x86)\AutoIt3\SciTE\..\AutoIt3_x64.exe"', _ 'C:\Program Files (x86)\AutoIt3\AutoIt3.exe', _ 'C:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe', _ '/ErrorStdOut', _ '"' & $sAutoItPath & '"', _ $sAutoItPath, _ '"' & @ScriptFullPath & '"', _ @ScriptFullPath _ ] For $sPattern In $aRemove $sCmd = StringReplace($sCmd, $sPattern, '') Next ; Normalize whitespace $sCmd = StringRegExpReplace($sCmd, '[\r\n]+', ' ') ; Replace line breaks $sCmd = StringRegExpReplace($sCmd, '\s{2,}', ' ') ; Collapse multiple spaces $sCmd = StringStripWS($sCmd, $STR_STRIPLEADING + $STR_STRIPTRAILING) Return $sCmd EndFunc ;==>_CleanCommandLine Func _GetAutoItPath() Local $sExeName = @AutoItX64 ? 'AutoIt3_x64.exe' : 'AutoIt3.exe' Local $aDirs[] = [ _ _WinAPI_ExpandEnvironmentStrings('%ProgramFiles%') & '\AutoIt3\', _ _WinAPI_ExpandEnvironmentStrings('%ProgramFiles(x86)%') & '\AutoIt3\', _ @ScriptDir & '\' _ ] For $sDir In $aDirs If FileExists($sDir & $sExeName) Then Return $sDir & $sExeName Next ; Fallback Return @ScriptDir & '\' & $sExeName EndFunc ;==>_GetAutoItPath Func _ExecuteCommand($sCommand) ; Start process with stdout/stderr redirection Local $iPID = Run($sCommand, '', @SW_HIDE, BitOR(0x1, 0x2, 0x4)) ; STDIN, STDOUT, STDERR If @error Or Not $iPID Then ConsoleWrite('! Error: Failed to start process.' & @CRLF) Return SetError(1, 0, 1) EndIf ; Get process handle for exit code Local $hProcess = _ProcessOpenHandle($iPID) If @error Then ConsoleWrite('! Warning: Failed to open process handle.' & @CRLF) EndIf ; Stream output (outputs are prefixed in child process) _StreamProcessOutput($iPID) ; Get exit code Local $iExitCode = _ProcessGetExitCode($iPID, $hProcess) _ProcessCloseHandle($hProcess) ; Log result Local $sTimeDiff = _FormatTimeSmart(TimerDiff($iTimeInit)) Local $sStatus = ($iExitCode == 0) ? '+' : '!' Local $sResult = ($iExitCode == 0) ? 'completed successfully' : 'failed' ConsoleWrite(StringFormat('%s [%02d:%02d:%02d] %s %s in %s. Exit code: %d%s', _ $sStatus, @HOUR, @MIN, @SEC, @ScriptName, $sResult, $sTimeDiff, $iExitCode, @LF)) Return SetError($iExitCode, 0, $iExitCode) EndFunc ;==>_ExecuteCommand Func _StreamProcessOutput($iPID) ; Optimized output streaming with smaller buffer reads Local $sStdOut, $sStdErr Local $bStdOutDone = False, $bStdErrDone = False While Not ($bStdOutDone And $bStdErrDone) ; Read stdout $sStdOut = StdoutRead($iPID) If @error Then $bStdOutDone = True ElseIf $sStdOut Then ConsoleWrite($sStdOut) EndIf ; Read stderr $sStdErr = StderrRead($iPID) If @error Then $bStdErrDone = True ElseIf $sStdErr Then ConsoleWrite($sStdErr) EndIf ; Small sleep to prevent CPU spinning (reduced from 5ms to 1ms) If Not ($bStdOutDone And $bStdErrDone) Then Sleep(1) WEnd EndFunc ;==>_StreamProcessOutput ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Time & Process Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Func _FormatTimeSmart($fMS) If $fMS < 1000 Then Return Round($fMS) & "ms" Local $iHours = Floor($fMS / 3600000) $fMS = Mod($fMS, 3600000) Local $iMinutes = Floor($fMS / 60000) $fMS = Mod($fMS, 60000) Local $iSeconds = Floor($fMS / 1000) Local $iMillis = Mod($fMS, 1000) Return StringFormat("%02d:%02d:%02d:%03d", $iHours, $iMinutes, $iSeconds, $iMillis) EndFunc ;==>_FormatTimeSmart Func _ProcessOpenHandle($iPID) Local $aCall = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'dword', $PROCESS_QUERY_INFORMATION, 'bool', False, 'dword', $iPID) If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) Return $aCall[0] EndFunc ;==>_ProcessOpenHandle Func _ProcessGetExitCode($iPID, $hProcess) If Not $hProcess Then Return 0 Local $aCall = DllCall('kernel32.dll', 'bool', 'GetExitCodeProcess', 'ptr', $hProcess, 'dword*', 0) If @error Or Not $aCall[0] Then Return 0 Return $aCall[2] EndFunc ;==>_ProcessGetExitCode Func _ProcessCloseHandle($hProcess) If Not $hProcess Then Return 0 DllCall('kernel32.dll', 'bool', 'CloseHandle', 'ptr', $hProcess) Return Not @error EndFunc ;==>_ProcessCloseHandle ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; API Hooking Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Func _AddHookApi($sModuleName, $vFunctionName, $vNewFunction, $sRet = "", $sParams = "") Local Static $pImportDirectory, $hInstance ; Initialize on first call If Not $pImportDirectory Then $hInstance = _GetModuleHandle() If @error Then Return SetError(1, 0, 0) Local $aCall = DllCall("dbghelp.dll", "ptr", "ImageDirectoryEntryToData", _ "handle", $hInstance, "boolean", True, "word", 1, "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(2, 0, 0) $pImportDirectory = $aCall[0] EndIf Local $bIsOrdinal = IsInt($vFunctionName) Local $bRestore = Not IsString($vNewFunction) Local $pDirectoryOffset = $pImportDirectory ; Iterate through import directory While True Local $tImport = DllStructCreate("dword RVAOriginalFirstThunk;" & _ "dword TimeDateStamp;dword ForwarderChain;" & _ "dword RVAModuleName;dword RVAFirstThunk", $pDirectoryOffset) If Not DllStructGetData($tImport, "RVAFirstThunk") Then ExitLoop Local $tModName = DllStructCreate("char Name[64]", $hInstance + DllStructGetData($tImport, "RVAModuleName")) If DllStructGetData($tModName, "Name") == $sModuleName Then Local $pThunk = $hInstance + DllStructGetData($tImport, "RVAFirstThunk") Local $pOrigThunk = $hInstance + DllStructGetData($tImport, "RVAOriginalFirstThunk") If $pOrigThunk == $hInstance Then $pOrigThunk = $pThunk Local $iOffset = 0 While True Local $tPtr = DllStructCreate("ptr", $pOrigThunk + $iOffset) Local $pValue = DllStructGetData($tPtr, 1) If Not $pValue Then ExitLoop Local $bMatch = False If $bIsOrdinal Then $bMatch = (BitAND($pValue, 0xFFFFFF) == $vFunctionName) Else Local $tName = DllStructCreate("ushort Ordinal;char Name[64]", $hInstance + $pValue) $bMatch = (DllStructGetData($tName, "Name") == $vFunctionName) EndIf If $bMatch Then Local $tFunc = DllStructCreate("ptr", $pThunk + $iOffset) If Not _VirtualProtect(DllStructGetPtr($tFunc), DllStructGetSize($tFunc), $PAGE_READWRITE) Then Return SetError(3, 0, 0) EndIf Local $pOld = DllStructGetData($tFunc, 1) Local $pNew = $bRestore ? $vNewFunction : DllCallbackGetPtr(DllCallbackRegister($vNewFunction, $sRet, $sParams)) DllStructSetData($tFunc, 1, $pNew) Return $pOld EndIf $iOffset += DllStructGetSize($tPtr) WEnd ExitLoop EndIf $pDirectoryOffset += 20 WEnd Return SetError(4, 0, 0) EndFunc ;==>_AddHookApi Func _VirtualProtect($pAddress, $iSize, $iProtection) Local $aCall = DllCall("kernel32.dll", "bool", "VirtualProtect", _ "ptr", $pAddress, "dword_ptr", $iSize, "dword", $iProtection, "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) Return True EndFunc ;==>_VirtualProtect Func _GetModuleHandle($vModule = 0) Local $sType = IsString($vModule) ? "wstr" : "ptr" Local $aCall = DllCall("kernel32.dll", "ptr", "GetModuleHandleW", $sType, $vModule) If @error Or Not $aCall[0] Then Return SetError(1, 0, 0) Return $aCall[0] EndFunc ;==>_GetModuleHandle ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; String & WinAPI Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Func _WinAPI_GetString($pString, $bUnicode = True) Local $iLen = _WinAPI_StrLen($pString, $bUnicode) If @error Or Not $iLen Then Return SetError(@error + 10, @extended, '') Local $sType = $bUnicode ? 'wchar' : 'char' Local $tString = DllStructCreate($sType & '[' & ($iLen + 1) & ']', $pString) If @error Then Return SetError(@error, @extended, '') Return SetExtended($iLen, DllStructGetData($tString, 1)) EndFunc ;==>_WinAPI_GetString Func _WinAPI_StrLen($pString, $bUnicode = True) Local $sFunc = $bUnicode ? 'lstrlenW' : 'lstrlenA' Local $aCall = DllCall('kernel32.dll', 'int', $sFunc, 'struct*', $pString) If @error Then Return SetError(@error, @extended, 0) Return $aCall[0] EndFunc ;==>_WinAPI_StrLen Func _WinAPI_ExpandEnvironmentStrings($sString) Local $aCall = DllCall("kernel32.dll", "dword", "ExpandEnvironmentStringsW", _ "wstr", $sString, "wstr", "", "dword", 4096) If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, "") Return $aCall[2] EndFunc ;==>_WinAPI_ExpandEnvironmentStrings Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal
argumentum Posted 4 hours ago Posted 4 hours ago 7 hours ago, Trong said: Even running with /ErrorStdOut still does not show the error on the console Because you need to "echo %ERRORLEVEL%". That is the "rc:1" on SciTE. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
argumentum Posted 2 hours ago Posted 2 hours ago ok, my bad I guess ( because I didn't test with errors as my code is always perfect ) AutoItCui.bat: @Echo OFF :: AutoItCui.bat ; name of the batch file that runs Autoit3cui Autoit3cui /ErrorStdOut /AutoIt3ExecuteScript %* echo rc:%errorlevel% With the above batch file you'd run your script. Say: Opt("SetExitCode",1) Global $a[1] $a[1] = 1 and the output would be: >Autoitcui MyFlaw.au3 "D:\Utilities\AutoIt3\MyFlaw.au3" (3) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.: $a[1] = 1 ^ ERROR rc:2147479674 were the 2147479674 errorlevel in hex is 0x7FFFF07A. So the code I posted in the beginning is all that is really needed. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
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