Hello a client of mine has a lot of VBSripts (VBS) that do various things. At the top of each script they reference a library of subs and functions like this:
Const ForReading = 1
Dim objFSO, objFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("Z:\path\VbsProcedures.vbs", ForReading)
Execute objFile.ReadAll()
'more code that uses the subs and functions in VbsProcedures.vbs
This way the subs and functions are available to the code below the lines. That is all good. I can work on the procedures all in one place. The issue is that when a procedure in VbsProcedures.vbs produces an error I don't get a line number to help me debug it. I just returns line 0 character 1, or something like that.
How do I get an error line number in this case?
I am wondering if there is a simple solution.
I can put If Err.Number <> 0 Then after every suspect line and echo out an error description like this https://technet.microsoft.com/en-us/library/ee692852.aspx, but that seems quite inefficient. You can't use GoTo somelabel statements in VBS to handle errors for large blocks of code like you can in VBA.
Edit: I can't post the VbsProcedures.vbs because it is my clients. I am looking for a general solution to the issue so I can debug better in general. I'm not looking for help debugging a specific issue right now. In fact there are no errors in it right now. Generally speaking, what is in the VbsProedures.vbs is routine Functions and Subs we use. Like this:
Option Explicit
'create formatted dates easily
Function sfFormatDate(sDateOld, sFormat)
'code omitted
sfFormatDate = sDateNew
End Function
'progress type of message
Function fScriptIsRunningNoticeStart()
'code omitted
fScriptIsRunningNoticeStart = objExplorer
End Function
TEMP EDIT2: (Attempting BuvinJ's suggestion.)
I think I have it working finally....
Contents of file test.vbs:
'Option Explicit
Const bINJECT_LOGGING=True
Sub Include( sRelativeFilePath )
' Get the library script
Dim oFs : Set oFs = CreateObject("Scripting.FileSystemObject")
Dim sThisFolder : sThisFolder = oFs.GetParentFolderName( WScript.ScriptFullName )
Dim sAbsFilePath : sAbsFilePath = oFs.BuildPath( sThisFolder, sRelativeFilePath )
Dim sLibrary : sLibrary = oFs.OpenTextFile( sAbsFilePath ).readAll()
' Perform compilation debugging
On Error Resume Next
Dim oSC : Set oSC = CreateObject("MSScriptControl.ScriptControl")
With oSC
.Language = "VBScript"
.UseSafeSubset = False
.AllowUI = False
.AddCode sLibrary
End With
With oSC.Error
If .Number <> 0 then
WScript.Echo sAbsFilePath & "(" & .Line & "," & .Column & ")" & _
" Microsoft VBScript compilation error: " & _
"(" & .Number & ") " & .Description
WScript.Quit
End If
End With
On Error Goto 0
' Implement optional runtime debugging via logging injections
If bINJECT_LOGGING Then
InjectRoutineLogging sLibrary, _
oFs.OpenTextFile( sAbsFilePath ), sRelativeFilePath
End If
' Import the Library
ExecuteGlobal sLibrary
End Sub
Sub InjectRoutineLogging( ByRef sLibrary, ByRef oFile, sFilePath )
sLibrary = ""
Dim sLine, sParseLine, sAppendLine, sPrependLine
Dim bIsRoutineBody : bIsRoutineBody = False
Dim sRoutineName : sRoutineName = ""
Dim aStartKeywords : aStartKeywords = Array( "SUB", "FUNCTION" )
Dim aEndKeywords : aEndKeywords = Array( "END SUB", "END FUNCTION" )
Do Until oFile.AtEndOfStream
sLine = oFile.ReadLine
sParseLine = Trim(sLine)
sPrependLine = ""
sAppendLine = ""
' Find routine signature starts (and the save name)
If sRoutineName = "" Then
For Each sKeyword In aStartKeywords
If Left( UCase(sParseLine), Len(sKeyword) ) = sKeyword Then
sParseLine = Right( sParseLine, _
Len(sParseLine)-Len(sKeyword) )
sRoutineName = Trim(Split( sParseLine, "(" )(0))
End If
Next
End If
If sRoutineName <> "" Then
If Not bIsRoutineBody Then
' Find end of routine signature
' (figuring in line continuations and eol comments)
' Inject start log
sParseLine = Trim(Split(sParseLine, "'")(0))
If Right( sParseLine, 1 ) = ")" Then
sAppendLine = "WScript.Echo" & _
"""Start " & sRoutineName & _
" (" & sFilePath & ")..." & """" & vbCrLF
bIsRoutineBody = True
End If
Else
' Find routine end
' Inject end log
For Each sKeyword In aEndKeywords
If Left( UCase(sParseLine), Len(sKeyword) ) = sKeyword Then
sPrependLine = "WScript.Echo ""...End " & _
sRoutineName & " "" "
sRoutineName = ""
bIsRoutineBody = False
End If
Next
End If
End If
' Append lines
If sPrependLine <> "" Then sLibrary = sLibrary & sPrependLine & vbCrLF
sLibrary = sLibrary & sLine & vbCrLF
If sAppendLine <> "" Then sLibrary = sLibrary & sAppendLine & vbCrLF
Loop
End Sub
WScript.Echo "test1"
Include "test_VbsProcedures.vbs" '"Z:\mypath\test_VbsProcedures.vbs"
WScript.Echo "test2"
call test_sub
WScript.Echo "test3"
Contents of file test_VbsProcedures.vbs is just:
sub test_sub()
WScript.Echo "test_sub"
end sub
Using the command in the cmd prompt:
"C:\Windows\SysWOW64\cscript.exe" "Z:\mypath\test.vbs"
I get:
test1
test2
Start test_sub (test_VbsProcedures.vbs)...
test_sub
...End test_sub
test3
I really appreciate your help BuvinJ's! Let me know if there is more to do here, but I think it is running! Next I'll break it to test it.
EDIT 3: If the lib has this:
option explicit
sub test_sub()
msgbox "testing msg"
WScript.Echo "test_sub"
s = 1
end sub
sub stack1()
call test_sub()
end sub
I get:
test1
test2
Start stack1 (test_VbsProcedures.vbs)...
Start test_sub (test_VbsProcedures.vbs)...
test_sub
Z:\mypath\test.vbs(0,
1) Microsoft VBScript runtime error: Variable is undefined: 's'
... so it looks like error line number is (0,1), which isn't correct.
EDIT 4: with lib as:
option explicit
sub test_sub()
msgbox "testing msg"
WScript.Echo "test_sub"
's = 1
dim x : x=(1
end sub
sub stack1()
call test_sub()
end sub
line number is working now!!
test1
Z:\mypath\test_VbsProcedures.vbs(11,12) Microsoft VBScript compilation error: (1006) Expected ')'
test1