Thanks for this excellent tutorial! I agree that having some consistent way
of structuring your code is most important - whether you follow ebgreen's
well-considered rules or modify them to better fit your circumstances is
secondary. To give you some ideas - not to criticize ebgreen's approach -
here are some of my deviations/variations:
Header:
The first line of my script looks like this:
'' filename.ext - the problem in a nutshell
'' Something.vbs - Demonstrate script organization
The benefit: I can use a grep tool to search for scripts:
C:\wis\_vbs\0506\dev\forum
tgrep -d "'' [^ ]+ - .*" .\vbstmplates\*.vbs
File .\vbstmplates\demostructure.vbs:
'' demostructure.vbs - Demonstrate script organization
File .\vbstmplates\excelado.vbs:
'' excelado.vbs - use ado for excel work
File .\vbstmplates\something.vbs:
'' something.vbs - Demonstrate script organization
File .\vbstmplates\tinterleave.vbs:
'' tinterleave.vbs - test interleave
C:\wis\_vbs\0506\dev\forum
tgrep -d "'' [^ ]+ - .*" .\vbstmplates\*.vbs | tgrep orga
File STDIN:
'' demostructure.vbs - Demonstrate script organization
'' something.vbs - Demonstrate script organization
Option Explict:
As this is such an important part of any decent VBScript program, I will
cite ebgreen
Use it. Always. Period.
to drive this rule home.
Constant and Variable Declaration:
I try to Dim my variables as close as possible to their first use, because
that reduces the number of lines you have to check to understand a variable.
What really causes me bad dreams (about programmers being nailed to doors by
bosses or customers because their messy scripts made rockets or oxygenators
explode) are lines like
Dim objFSO, objTextfile, objNewTextFile, objXL, arrEmailLog, i, count, s, arrignore, arrdate, strdate, arrtime
at the top of the script. I bet $100 that at least one item of the list isn't used
in the code, so a maintainer will have to double check all of them and ponder for
the unused ones whether they are missing by design or accident. (I win - see
http://www.visualbasicscript.com/fb.ashx?m=80312 - I stopped bothering after "objNewTextFile" and "arrignore")
I'm more concerned about types and scopes as ebgreen is. So instead of
'Global Variables
Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")
Dim strTestVariable
I have
'Global Variables
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
see below why "Dim strTestVariable" got lost.
Main Code:
Decent programming languages like C, Java, or C# don't allow top level code out
of the entrypoint function/method. Languages that started with the principle
"First line of code not in a function/sub/class/method is executed immediately"
were improved upon in later versions (VB -> VB.NET, to mention just one). I admit
that such a change is often linked to a transition from a scripting language to
compiled language, so you could argue that a main function is overkill for
VBScript. I say: Put your 'real' code in a main function in any case, but exploit
the immediate execution where it brings benefits (.hta resize, library includes).
Instead of
'Main Code
strTestVariable = "This is where the main flow of the script goes"
WScript.Echo strTestVariable
I prefer
'Main Code
WScript.Quit TrivialMain() ' the one and only top level code line
' TrivialMain - just show we are living
Function TrivialMain()
TrivialMain = 1 ' assume error
Dim sMsg : sMsg = "This is where it really starts."
WScript.Echo sMsg
' ....
TrivialMain = 0 ' came to here, so it seems ok
End Function
The benefits:
(1) doing a botch job by creative use of globals will be more difficult
(read/study
http://www.visualbasicscript.com/fb.ashx?m=81456 )
(2) You can work with different (sub)problems and variations of their
solution by writing and then selecting many 'main' functions in
the same script:
'Main Code (select function to call by re-ordering or commenting (out)
'WScript.Quit TrivialMain() ' the one and only top level code line
WScript.Quit createTestData()
WScript.Quit reportWithExcel()
WScript.Quit reportWithADO()
....
(3) You can use a nearly global "On Error Resume Next" that can be 'switched
off' at runtime
'' oern.vbs - professional OERN
Option Explicit
' Global Constants
' Global Variables
Dim oWAN : Set oWAN = WScript.Arguments.Named
' Main Code
If oWAN.Exists( "debug" ) Then
WScript.Quit Main()
Else
Dim nErrorLevel : nErrorLevel = 2
On Error Resume Next
nErrorLevel = Main()
If 0 <> Err.Number Then
WScript.Echo Err.Number, Err.Description
WScript.Echo "fatal error, but no abort - and no line # either"
End If
WScript.Quit nErrorLevel
End If
' Main - cause an error
Function Main()
Main = 1 ' assume error
Dim nRes : nRes = 15 / CInt( oWAN( "num" ) )
WScript.Echo "The answer is", nRes
Main = 0 ' came to here, so it seems ok
End Function
using it:
C:\wis\_vbs\0506\dev\forum\vbstmplates
cscript oern.vbs /num:0
11 Division durch Null
fatal error, but no abort - and no line # either
C:\wis\_vbs\0506\dev\forum\vbstmplates
cscript oern.vbs /num:3
The answer is 5
C:\wis\_vbs\0506\dev\forum\vbstmplates
cscript oern.vbs /num:0
11 Division durch Null
fatal error, but no abort - and no line # either
C:\wis\_vbs\0506\dev\forum\vbstmplates
cscript oern.vbs /num:0 /debug
C:\wis\_vbs\0506\dev\forum\vbstmplates\oern.vbs(27, 14) Laufzeitfehler in Microsoft VBScript: Division durch Null