5 - 6

5. VBScript project with multi-files

任何真正实用的工程开发都必然是多文件的。但是VBScript创建多文件工程要麻烦一点,它对多文件工程,代码复用的支持并不是太好。在C/C++工程里,我们已经习惯了通过一个include语句,并且声明一个函数原形的方式来使用其它模块中的函数,这样一个复杂的工程可以比较容易地分解成一些小的模块,以更容易理解和掌握。VBScript中情况有些不同。这与它的设计目标有关。最初VBScript是用在客户端脚本,以支持与客户端作简单的交互,如简单的输入检查等等。在浏览器里显然没有办法支持对另一个文件中的函数的调用,你不知道那个文件是否存在,何时存在。那么以本地脚本形式执行的VBScript又怎么样呢?想想看这条命令:cscript.exe yourscript.vbs。显然一个VBS运行在一个进程空间里(cscript进程),它也没有办法得到另一个文件中的函数。

认识到了VBScript的局限性,我们来看如何解决它。

第一种需要可能是需要在一个脚本运行的中间直接运行另外一个脚本。这可以通过下面的方法来完成:

Set WSHShell = CreateObject("WScript.Shell")
WSHShell.Run "wscript c:/Test.vbs param1", , True

注意到这里我们Test.vbs运行在另外一个进程空间(wscript进程)里,加上执行当前脚本的WSH,我们一共有两个进程。这是通过WSHShell.Run来做到的,这个方法的原型是:

object.Run(strCommand, [intWindowStyle], [bWaitOnReturn])

如果时序很重要,你可以在bWaitOnReturn这个参数中指定主脚本是否要等待被执行的脚本运行结束后才能继续。

另一点需要注意的地方是strCommand参数,这个参数是一个复合体,以空格区分各个域。如果需要将运行参数传递给被调用的脚本,应该在第二个空格后面输入。下面的例子显示了如何获取主脚本传递来的参数。对了,是通过WScript.Arguments来访问。WSCript还有其他一些有趣的属性,请记得读一下文档。

Set oArgs = WScript.Arguments
For i = 0 to oArgs.Count - 1
   WScript.Echo oArgs(i)
Next

关于参数解析,这里给出一个Windows 2000 support tools中的一个脚本的例子。你可以复用这个函数,以解析任何以/ArgName:Value形式指定的参数。

' searches for and returns the value of a command line argument of the form
' /argName:value from the supplied array.  erases the entry in the array so
' that only untouched entries remain.

function GetArgValue(argName, args())
    dim a
    dim v
    dim argNameLength
    dim x
    dim argCount
    dim fullArgName

    fullArgName = "/" & argName & ":"
    argCount = Ubound(args)

    ' Get the length of the argname we are looking for
    argNameLength = Len(fullArgName)
    GetArgValue = "" ' default to nothing
   
    for x = 0 To argCount
        if Len(args(x)) >= argNameLength then

            a = Mid(args(x), 1, argNameLength)
            if UCase(a) = UCase(fullArgName) then

                ' erase it so we can look for unknown args later
                v = args(x)
                args(x) = ""

                if Len(v) > argNameLength then
                    GetArgValue = Mid(v, argNameLength + 1)
                    exit function
                else
                    GetArgValue = ""
                    exit function
                end if
            end if
        end if
    next
end function

 更多的时候,我们需要在脚本之间共享变量,以及相互调用函数。我们想要得到C/C++中那样的便利性:通过一个Include声明,就可以将另外一个模块中的函数和变量引入到当前的模块中。在VBScript中,可以通过ExecuteGlobal来实现:

Sub Include(sInstFile)
    Dim oFSO, f, s
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    Set f = oFSO.OpenTextFile(sInstFile)
    s = f.ReadAll
    f.Close
    ExecuteGlobal s
End Sub

这样,在脚本中加上这样一句调用:Include "mylib.vbs",就可以使用mylib.vbs中声明的全局变量和函数了!注意这里的函数ExecuteGlobal有一个类似的函数Execute,这里如果使用Execute的话,就达不到我们想要的效果。因为通过Execute暴露的名字,其作用范围局限于Execute所处的级别,在这里,也就是在函数Include内部。这几乎肯定不是你想要的结果。

还有别的方法吗?是的。VBScript内在的支持COM方式。如果可以将你的脚本编译成一个COM组件,就当然可以在别的脚本中调用组件中的方法了。恰好,MS提供了工具Script Component Wizard来帮助我们将一些VBScript文件打包成一个组件,并提供注册方法。 

现在我们来学一些新的方法。我的意思是,这些方法是仅为WSH支持的,你可能以前并没有遇见过。WSH支持一种叫*.wsf的文件,这个文件本身是XML格式的,通过该文件可以将你的VBScript脚本,以及其它类型的脚本,比如batch,perl等等组装在一起,交给WSH来执行。这方面文档还算详细,这里就不多介绍了。

这一节里,介绍了由单个脚本文件组装成一个较大的工程的四种方法,通过运用这些方法,你可以建立自己的常用函数库,在各个脚本之间共享变量和传递数据,等等。

6. Error handling in VBScript

说到错误和异常处理,高级开发语言一般会提供断言,try-catch或返回值机制。坦率地说,VBScript提供的异常处理机制,甚至比它同家族的其他成员都要来得弱。这可能会阻止一些“真正的”程序员使用VBScript开发语言,毕竟,不能对错误和异常有足够的控制力,是一件很让人不安的事。但是考虑到VBScript应该应用的场合和面向的对象,我们不应该诘难VBScript语言的设计者。VBScript脚本绝大多时候用于执行有人值守,轻量级的系统管理任务,而且要宜于编写和快速完成–不可能让编写脚本的花的时间比人工执行这些管理任务还要费时!当然,VBScript语言正在获得更加广泛的应用,有些应用还十分关键,比如,QuickTestPro已经选用它作为测试脚本语言。如果你也用VBScript来完成一些关键应用,比如super lab测试,建议认真阅读本节,以真正了解VBScript在应付异常方面和错误恢复的能力。

关于VBScript的异常处理机制,似乎两个声明语句和一个变量就是全部,它们是Err对象和:

on error resume next
on error goto 0
声明语句。

从语义上看,On error resume next似乎直观一些,它好象是在说没有错误处理,直接换下一句执行。而On error goto 0是什么意思?需要在程序中添加一个标号为0的错误处理例程吗?

Basic语言的早期使用者应该对行号不陌生。正确的行号从1开始,0是非法行号。因此On error goto 0在这里并不意味着跳转,反而意味着关闭错误处理。

On error resume next和On error goto 0声明了一个错误处理的作用域。在这个作用域里发生的错误会被脚本(程序员)捕获到。而不在任何上述作用域以外的地方发生的异常,会引起脚本执行终止。记住错误处理作用域支持嵌套,下面的两个例子都是有效的,当然第二个看上去略为有意义一些:

例1:

Sub Blah2()
      WScript.Echo "Blah2 Start"
      Err.Raise InvalidCall
      WScript.Echo "Blah2 End"
End Sub

On Error Resume Next
WScript.Echo "line 1"
Blah2
On Error Resume Next
WScript.Echo "line 4"
Blah2
On Error GoTo 0
WScript.Echo "line 7"
On Error GoTo 0
WScript.Echo "line 9"

例2:

Sub Blah2()
      WScript.Echo "Blah2 Start"
      Err.Raise InvalidCall
      WScript.Echo "Blah2 End"
End Sub

Sub foo()
 On Error Resume Next
      Blah2
 On Error GoTo 0
End Sub

On Error Resume next
     WScript.Echo "start"
     foo
     WScript.Echo "end"
On Error GoTo 0

在例2中我对On Error对(pair)中间的语句进行了缩进。这正是我想表达的意思,简练地说,可以把这个对(pair)看成一个合并的Try–Catch,错误捕获和处理在一起完成,或者说错误处理必须是内联的,不允许跳到别的什么行号或标记处去执行,这在其他基于basic的语言中是允许的。正如Try–Catch的辗转解开一样,On Error pair也有类似的属性。在例2中,如果foo()过程定义如下:

Sub foo()
     WScript.Echo "foo start"
     Blah2
     WScript.Echo "foo end" 
End Sub

则过程Blah2中发生的抛出的异常,会导致WSCript.Echo "foo end"无法被执行,而直接跳到WSCript.Echo "end"一句,因为只有在这里才找到一个"Try"声明(On Error Resume Next),堆栈的辗转开解才结束。按照On Error Resume Next的语义,应该从当前调用栈的下一语句执行,即WSCript.Echo "end"。

在过程Blah2中,我使用了Err对象,现在是时候谈谈这个对象了。首先,在任何时候,任何地方都可以使用这个对象。Err对象有三个属性,缺省属性number,description和source。

Number是缺省属性,所以这样的比较if (6 = Err)是允许的。VBScript允许的错误码在1 - 65535范围内(VBScript+用户)。我不是很清楚用户自定义错误码可以使用的范围,但帮助文档说,在自动化对象中使用自定义错误码,应该从vbObjectError + 1处开始。Source代表着应用程序标识或者一个类对象说明(COM),也可以在自定义异常中,直接添加脚本文件名和行号进来,以方便调试。遗撼的是,并没有__FILE__和__LINE__这样的宏可以使用,因此添加文件名和行号是件很费时的事。

Err对象的初始化值是number = 0,description = ""。当On Error Resume Next和On Error Goto 0以及方法Clear被调用时,Err被初始化。Raise方法比较直观,它的原型是:

object.Raise(number, source, description, helpfile, helpcontext)

最后,提供一个错误处理函数。这个错误处理函数其实不做处理,它只是输出错误信息并退出脚本执行。

sub DumpErrAndQuit(strObj, strErrReportMethod)
   dim errnum
   errnum = Err.Number

   wscript.Echo "Error 0x" & CStr(Hex(errnum)) & " occurred."
   if len(Err.Description) Then
      wscript.Echo "Error Description: " & Err.Description
   end If
   if len(Err.Source) then
      wscript.Echo "Error Source     : " & Err.Source
   end If
  
   if len(strObj) Then
    wscript.Echo "Special Description: "
    Dim CmdStr
    CmdStr = "wscript.Echo " & strObj & "." & strErrReportMethod
    Execute CmdStr
   End If
   wscript.quit(0)
end Sub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值