How to implement error handling? - error-handling

My AutoIt script generates an error that I want to handle. A way that any error goes to a custom function will also do. In VBA I use OnErrorGoTo, but I am unable to find something similar in AutoIt.
My Code :
Func Start()
While 1
If ProcessExists ( "Photoshop.exe" ) <> 0 Then
Sleep(5000)
Else
Local $sFile ="C:\Auto\CodeToBe\Batch\Image Process-50-2D v.2-" & $n & ".jsxbin"
Local $iPID = ShellExecute($sFile)
Sleep(10000)
$n = $n+1
EndIf
WEnd
EndFunc
An error will occur when $n exceeds the number of files in that folder. I tried this but didn't work (from the "HELP SECTION" and a forum post):
Global $iEventError = 0 ; To be checked to know if COM error occurs. Must be reset after handling.
Local $oMyError = ObjEvent("AutoIt.Error", "ErrFunc") ; Install a custom error handler
Func Start()
While 1
If ProcessExists ( "Photoshop.exe" ) <> 0 Then
Sleep(5000)
Else
Local $sFile ="C:\Auto\CodeToBe\Batch\Image Process-50-2D v.2-" & $n & ".jsxbin"
Local $iPID = ShellExecute($sFile)
If $iEventError Then
MsgBox($MB_OK, "", "There was an error on the previous line.")
$iEventError = 0 ; Reset after displaying a COM Error occurred
EndIf
Sleep(10000)
$n = $n+1
EndIf
WEnd
EndFunc
; This is my custom error handler
Func MyErrFunc()
Msgbox(0,"","ERROR GENERATED ON " & $n)
Endfunc

I recommend the second example because it prevents an error in the first place. However, the first example can be used as a general error checker.
Example 1
Start()
Func Start()
Local $n = 1
While 1
If ProcessExists("Photoshop.exe") <> 0 Then
Sleep(5000)
Else
Local $sFile = "C:\Auto\CodeToBe\Batch\Image Process-50-2D v.2-" & $n & ".jsxbin"
Local $iPID = ShellExecute($sFile)
If #error Then MyErrFunc(#ScriptLineNumber, #error) ;check for error
Sleep(10000)
$n = $n + 1
EndIf
WEnd
EndFunc ;==>Start
; error handler
Func MyErrFunc($iLineNumer, $iError)
$iLineNumer = $iLineNumer - 1
MsgBox(0, "", "ERROR GENERATED ON SCRIPT LINE: " & $iLineNumer & #CRLF & "ERROR CODE: " & $iError)
EndFunc ;==>MyErrFunc
Example 2
Start2()
Func Start2()
Local $n = 1
While 1
If ProcessExists("Photoshop.exe") <> 0 Then
Sleep(5000)
Else
Local $sFile = "C:\Auto\CodeToBe\Batch\Image Process-50-2D v.2-" & $n & ".jsxbin"
If FileExists($sFile) Then
Local $iPID = ShellExecute($sFile)
Sleep(10000)
Else ;handle error (you could use a function here if you wanted)
ConsoleWrite("File not found: " & $sFile & #CRLF)
EndIf
$n = $n + 1
EndIf
WEnd
EndFunc ;==>Start2

Try to implement error checking.
If Not FileExists(your string with the $n) Then
... abort
Else
shellexecute ...
You could use _FileListToArray() instead.

An error will occur when $n exceeds the number of files in that folder.
As per Documentation - Function Reference - _FileListToArray() :
Lists files and\or folders in a specified folder (Similar to using Dir with the /B Switch)
Will loop over existing filenames only (avoiding error altogether). Example:
#include <File.au3>
Global Const $g_sPathFiles = 'C:\Auto\CodeToBe\Batch\'
Global Const $g_sMaskFile = '*.jsxbin'
Global Const $g_aFile = _FileListToArray($g_sPathFiles, $g_sMaskFile, $FLTA_FILES, True)
For $i1 = 1 To $g_aFile[0]
ShellExecuteWait($g_aFile[$i1])
Next
Alternatively _FileListToArrayRec() may be used.
Related.

Related

resolve multiple conditions problem in autoit

I am working on a program in autoit. Unfortunately, I am getting problems in the following multiple conditions phase:
Here is my full code:
My code:
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
Example()
Func Example()
; Create a GUI
Local $hGUI = GUICreate("my program", 300, 200)
; Create a combobox control.
Local $idComboBox = GUICtrlCreateCombo("", 10, 10, 185, 20)
Local $idButton = GUICtrlCreateButton("Activate", 210, 140, 85, 25)
Local $idButton_Close = GUICtrlCreateButton("Close", 210, 170, 85, 25)
; Add additional items to the combobox.
GUICtrlSetData($idComboBox, "Arabic|French|English", "Arabic")
; Display the GUI.
GUISetState(#SW_SHOW, $hGUI)
Local $sComboRead = ""
; Loop until the user exits.
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $idButton_Close
ExitLoop
Case $idButton
$sComboRead = GUICtrlRead($idComboBox)
; defining language codes
if $sComboRead = "Arabic" then $slktar = "ar-MA"
if $sComboRead = "French" then $slktfr = "fr-FR"
if $sComboRead = "English" then $slkten = "en-US"
local $slktlng = #ComSpec & " /K " & '"' & #ScriptDir & "\bin\prog.exe enable_language " ;main operation witout the addinional language code
case $slktar
Run($slktlng & " " & $slktar, #ScriptDir & "\bin\", #SW_HIDE) ; starting main operation + arabic language code
case $slktfr
Run($slktlng & " " & $slktfr, #ScriptDir & "\bin\", #SW_HIDE) ; starting main operation + french language code
case $slkten
Run($slktlng & " " & $slkten, #ScriptDir & "\bin\", #SW_HIDE) ; starting main operation + english language code
EndSwitch
WEnd
GUIDelete($hGUI)
EndFunc
I have no idea of it. Any help would be very much appreciated.
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
Example()
Func Example()
Local $sLanguage
; Create a GUI
Local $hGUI = GUICreate("my program", 300, 200)
; Create a combobox control.
Local $idComboBox = GUICtrlCreateCombo("", 10, 10, 185, 20)
Local $idButton = GUICtrlCreateButton("Activate", 210, 140, 85, 25)
Local $idButton_Close = GUICtrlCreateButton("Close", 210, 170, 85, 25)
; Add additional items to the combobox.
GUICtrlSetData($idComboBox, "Arabic|French|English", "Arabic")
; Display the GUI.
GUISetState(#SW_SHOW, $hGUI)
Local $sComboRead = ""
; Loop until the user exits.
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $idButton_Close
ExitLoop
Case $idButton
$sComboRead = GUICtrlRead($idComboBox)
local $slktlng = '"' & #ComSpec & '" /C "' & #ScriptDir & '\bin\prog.exe" enable_language'
; Define language code.
Switch $sComboRead
Case "Arabic"
$sLanguage = "ar-MA"
Case "French"
$sLanguage = "fr-FR"
Case "English"
$sLanguage = "en-US"
EndSwitch
Run($slktlng & " " & $sLanguage, #ScriptDir & "\bin\", #SW_HIDE)
EndSwitch
WEnd
GUIDelete($hGUI)
EndFunc
You can use another switch statement to define the language code.
Not sure why you would use separate variable names for the
language code though I used a common name $sLanguage to
be assigned the selected language code.
This helps to avoid duplication of code i.e only one
Run() function call needed, instead of three.
Also fixed the quoting of the command stored in $slktlng.
I changed the argument of /K to /C so ComSpec automatically
closes when done.

Facter ignoring variables at runtime

I have a Facter custom fact for use in Puppet that should generate a list of specific information, but it doesn't always work correctly, even on servers running the exact same versions of ruby, facter, puppet, and mysql. The code is below:
#backends.rb
puts "Backends retrieval"
if Facter.value('demainversion') == '2'
dbasename = Facter.value('dbasename')
if dbasename == ''
dbasename = 'database'
end
mysqlcmd = "mysql -uUser -pPassword #{dbasename} --skip_column_names -e "
if Facter.value('clustered')
dbasename = Facter.value('dbasename')
mysqlcmd = "mysql -uUser -pPassword -hclustered-host #{dbasename} --skip_column_names -e "
end
puts mysqlcmd
clients = Facter.value('databases').split(', ')
if clients != ''
clients.each do |client|
count = 0
client_id =
res =
backends = ""
facter_name = "#{client.gsub(' ','_')}_backends"
Facter.add("#{facter_name}") do
setcode do
puts "#{client} listing"
client_id = %x[#{mysqlcmd}"SELECT id FROM UserGroup WHERE groupName='#{client.strip}'"].strip
puts "#{client_id} listing"
puts backends
res = %x[#{mysqlcmd}"SELECT sourceMachine,sourceUser FROM GrabberJob WHERE clientGroup_id=#{client_id.strip}"].strip
res.each do |row|
machine = row.split(' ')[0]
login = row.split(' ')[1]
val = login.gsub('admin','')
if count == 0
backends << machine.strip << "(" << val << ")"
else
backends << ", " << machine.strip << "(" << val << ")"
end
count += 1
end
backends.strip
end
end
end
end
end
When puppet (or irb) runs this it may (or may not) return ...
ERROR 1046 (3D000) at line 1: No database selected
... but if the server throws the error it will continue to exhibit the problem. I know that the dbasename variable is set correctly, courtesy of the puts statements used for debugging, but the variable is ignored when the mysql commands are actually run.
I have also tried adding a USE #{dbasename}; statement to the client_id and res commands to no avail. Any suggestions on what I could do to make it work consistently would be most appreciated.

Filling PDF with AutoIT scripts

I am trying to fill a PDF fillable form using AUtoIT by using scripts. To make my agents works easy going. I ma trying to fill the pdf fields. Initially I am testing on single field Fname_c[0] ,but its not filling with value
Below is the code what i tried
$FilePath = "Form.pdf"
If $FilePath =-1 Then
MsgBox(0, "Error", "No file.")
Exit
EndIf
$fieldname = "Fname_C[0]"
$fileOut = "Form2.pdf"
$App = ObjCreate("AcroExch.App")
$AVDoc = ObjCreate("AcroExch.AVDoc")
If $AVDoc.Open($FilePath, "") Then
$PDDoc = $AVDoc.GetPDDoc
$AForm = ObjCreate("AFormAut.App")
$EX = "" _
& ' var f = this.getField("' & $fieldname & '")' & #LF _
& ' f.value = "Sunil"'
$AForm.Fields.ExecuteThisJavaScript($EX)
$PDDoc.save(1, $fileOut)
$App.closeAlldocs()
$App.exit()
Else
MsgBox(0, "", "Coudn't open report")
EndIf
;; release objects
$AForm = 0
$AVDoc = 0
$PDDoc = 0
$App = 0
where i am doing wrong?

Removing binary zero from a string

I've had to move a whole directory structure (thousands of directories and files) from the Mac to the PC, but now on the PC for some reason some of the folder names have a character on the end of value binary zero ( a few have this in the middle). I need to clean this up since it crashes a macro which tries to read these directories.
I've tried the following code in a vba-word macro using the Replace function (as part of a larger program that walks through the directory tree) but the Replace function doesn't seem to catch chr(0) .
Set current_folder = fso.GetFolder(source_folder.Path)
current_folder_name = current_folder.Name
cleaned_folder_name = Replace(current_folder_name, Chr(0), " ")
Selection.TypeText "Old directory name: " & current_folder_name
Selection.TypeParagraph
Selection.TypeText "New directory name: " & cleaned_folder_name
Selection.TypeParagraph
If current_folder_name <> cleaned_folder_name Then
current_folder.Name = cleaned_folder_name
End If
I've also tried:
cleaned_folder_name = Replace(current_folder_name, Chr(0), " ", 1, -1, vbBinaryCompare)
How I can get the Replace function to replace binary 0 in a string by a blank.
Or does anyone knows a different approach to cleaning up these directory and file names that would work.
Thanks,
Harry
This should do it:
Dim OldFolderName As String, NewFolderName As String
OldFolderName = source_folder.Path
If InStr(OldFolderName, Chr(0)) > 0 Then
'NewFolderName = Application.Clean(OldFolderName) 'Works on some versions
NewFolderName = Application.WorksheetFunction.Clean(OldFolderName) 'By Gene Skuratovsky
Name OldFolderName As NewFolderName
End If
Edit2: Probably best to use the Clean() method.
In my case Replace() and InStr() don't work with Chr(0) (can't see it not displaying any error), but this removal can be done for example this way:
If Mid$(str, 1, 1) = Chr$(0) Then str = Mid$(str, 2)
If Mid$(str, Len(str), 1) = Chr$(0) Then str = Left$(str, Len(str) - 1)
This is Null removal from ends, for example from objFile.ExtendedProperty("Dimensions") value, like "?600 x 400?". Nulls (?) are insterted here in Windows 10 but not in Windows XP.
You can write a custom loop function to determine what character you are having issues with:
OldFolderName = source_folder.Path
For x = 0 To 255
If InStr(OldFolderName, Chr(x)) > 0 Then
MsgBox "Chr(" & x & ") is found at position " & InStr(OldFolderName, Chr(x))
EndIf
Next x

VBS script return expected result, how to compare float value?

I am getting an interesting result when executing the following VB script.
Set StdOut = WScript.StdOut
Set wbemSvc = GetObject("winmgmts://" & "." & "/root/cimv2")
Set biosSet = wbemSvc.ExecQuery("Select * from Win32_BIOS")
For Each biosObj In biosSet
StdOut.WriteLine "SMBIOSMajorVersion=" & biosObj.SMBIOSMajorVersion
StdOut.WriteLine "SMBIOSMinorVersion=" & biosObj.SMBIOSMinorVersion
Next
StdOut.WriteLine "Return value is: " & IsNewBiosVersion
Function IsNewBiosVersion()
On Error Resume Next
Set biosSet = wbemSvc.ExecQuery("Select * from Win32_BIOS")
newBios = 0
For Each bios In biosSet
minorFloat = "." & bios.SMBIOSMinorVersion
If bios.SMBIOSMajorVersion > 2 OR (bios.SMBIOSMajorVersion = 2 AND minorFloat >= .6) Then
newBios = 1
End If
Next
IsNewBiosVersion = newBios
End Function
The result is as follow. This looks contradictory since the SMBIOSMinorVersion=4, according to the code logic in the script, the return value should be 0!!!
SMBIOSMajorVersion=2
SMBIOSMinorVersion=4
Return value is: 1
I ran this same script on another system and got the expected correct result.
SMBIOSMajorVersion=2
SMBIOSMinorVersion=4
Return value is: 0
So what is the problem here?
New update:
We execute the following script again on the system, and found that the CDbl() function does not convert the string "2.4" to double value correctly, instead it converts it to 24! Looks like the dot "." was lost when converting, what is wrong with this? An bug in CDbl or a violation when use it?
here is the script
Set StdOut = WScript.StdOut
StdOut.WriteLine ""
StdOut.WriteLine "Simple Function to Test BIOS Version"
StdOut.WriteLine ""
Set wbemSvc = GetObject("winmgmts://" & "." & "/root/cimv2")
Set biosSet = wbemSvc.ExecQuery("Select * from Win32_BIOS")
For Each bios In biosSet
newBios = 0
StdOut.WriteLine "SMBIOSMajorVersion=" & bios.SMBIOSMajorVersion
StdOut.WriteLine "SMBIOSMinorVersion=" & bios.SMBIOSMinorVersion
temp = bios.SMBIOSMajorVersion & "." & bios.SMBIOSMinorVersion
StdOut.WriteLine "major dot minor=" & temp
currentBios = CDbl(bios.SMBIOSMajorVersion & "." & bios.SMBIOSMinorVersion)
StdOut.WriteLine ""
StdOut.WriteLine "currentBios=" & currentBios
If currentBios >= 2.6 Then newBios = 1
StdOut.WriteLine "return value is: " & newBios
Next
here is the output
Simple Function to Test BIOS Version
SMBIOSMajorVersion=2
SMBIOSMinorVersion=4
major dot minor=2.4
currentBios=24
return value is: 1
Remove your error handling - it s probably suppressing an issue.
On Error Resume Next ' Not a good idea
For one thing you are comparing a string to a double in these lines:
minorFloat = "." & bios.SMBIOSMinorVersion
If bios.SMBIOSMajorVersion > 2 OR (bios.SMBIOSMajorVersion = 2 AND minorFloat >= .6) Then
Why not just convert the major.minor values to floating-point for your test? You're currently doing two separate tests, with one being a string vs float comparison, which is unusual.
Maybe try this instead?
currentBios = CDbl(bios.SMBIOSMajorVersion & "." & bios.SMBIOSMinorVersion)
If currentBios >= 2.6 Then newBios = 1
You have to be careful comparing floating-point values when math operations are involved but for literal values you'll be fine.
And, as already mentioned, remove On Error Resume Next or you may never know why it works on one PC but not another.