捕获VBScript中的任何错误?

时间:2010-05-28 14:08:38

标签: windows vbscript batch-file

我有一个调用VBScript(.vbs)程序的批处理文件。调用它之后,我的批处理脚本检查%errorlevel%以查看.vbs程序是否失败。我可以使用WScript.Quit(1)在.vbs程序中使用退出代码来表示失败。

但是,我只能明确地这样做。如果发生了一些意外的运行时错误,.vbs将退出并显示一个错误对话框,但是退出代码为零,因此我的批处理文件认为它已经超过了!我该如何改变这种行为?

如果你想说,请使用on error goto,不要打扰......普通VB中的语法可用,但VBScript中没有。

5 个答案:

答案 0 :(得分:5)

我想到了一个开箱即用的解决方案......谁说0必须意味着成功? VBScript有时会为失败返回0返回码,那么为什么不接受呢?采用0作为(至少一个可能的)故障代码并组成另一个数字(例如10)作为“成功代码”。

在脚本结束时,输入WScript.Quit(10)。只有在一切顺利到达那一点时才会被击中。然后,而不是调用批处理文件中的“if errorlevel 1”,使用“if%errorlevel%== 10”

答案 1 :(得分:4)

编辑:暂时(见警告)提出这个问题,我很快就开始认为这是一个非常糟糕的主意,但我把它留给了后代。不使用此功能的最令人信服的理由来自微软的 Eric Lippert ,他致力于设计与开发。 VBScript的实现。他说,in answer to another question VBScript不保证终结者总是运行。这可能意味着在未处理错误的情况下,这有时不会返回非0退出代码。

我想我个人将来会使用一个“从cscript退出代码中减去1的封装批处理文件”。


我喜欢fmunkert链接的解决方案,但我认为它需要您将代码放在特定的Class_Initalize中,这最多是笨拙的。我设计了一个不需要这个的相关解决方案;您只需在代码末尾“提交”成功的结果;如果未调用,则任何异常都会导致ExitCodeHandler的Class_Terminate实例设置非零退出代码。

Option Explicit

Class ExitCodeHandler
   private exit_code
   Public Sub Commit()
        exit_code = 0
   End Sub
   Private Sub Class_Initialize()
      exit_code = -1 ' this exit code will be returned if Commit is never called
   End Sub
   Private Sub Class_Terminate()
      if exit_code<>0 then WScript.Quit(exit_code)
   End Sub  
   Public Sub Quit(exitCode)
      Commit
      WScript.Quit(exitCode) ' exit code will be respected since we have committed
   End Sub
End Class

' create one of these at the start:
Dim ech: Set ech = New ExitCodeHandler

WSCript.StdOut.WriteLine "Hello"
s = "" ' undeclared variable causes runtime error - comment out to see success.

' WScript.Quit(-4) '  before a commit, -1 is returned due to the Class_Terminate

' Commit at the end
ech.Commit

' WScript.Quit(-5) '  after a commit, -5 is returned

请注意,这个习惯用法在C ++中被大量使用,它被称为RAII (Resource Acquisition Is Initialization)

你当然可以修改这个类以支持其他退出代码,错误消息等。你可能想把它放在一个普通的vbs文件中并使用mechanism for includes in vbscript来共享它。

注意事项

由于VBScript中的异常,我不知道在堆栈展开期间调用WScript.Quit的缺点的全部细节。我发现了以下内容:

  1. 谨慎使用。当我看到fmunkert的链接建议时,我已经想出了这个并且用它来探索,而不是广泛使用它。
  2. 如果明确调用WScript.Quit( n ),则ExitCodeHandler将使用自己的退出代码替换 n 。解决方法是在调用WScript.Quit之前始终调用ExitCodeHandler.Commit,或者调用提供的ExitCodeHandler.Quit而不是为您执行此操作。但是,依赖这两种方法中的任何一种方法可能并不总是实用/可行,而且它是非常惯用的,可能不会对维护者产生负面影响。
  3. 如果任何其他具有Class_Terminate的对象被终止(即 ExitCodeHandler的Class_Terminate之后调用WScript.Quit),您似乎会收到错误。您可能会遇到与正在销毁的任何COM对象类似的行为。我不知道VBScript以什么顺序销毁对象(或者即使它是有保证的),所以I've asked about it in another question

答案 2 :(得分:2)

正如你所说,所有可用的都是On Error Resume Next,所以你被迫使用这种模式:

On Error Resume Next
 ThingWithAChanceOfThrowingAnError ...
If (Err.number <> 0) then PrintErrorAndQuitWith1(Err.Description)

答案 3 :(得分:2)

如果是一个选项,你可以使用jscript代替它,它更好地支持异常处理,包括在任何异常上返回非零退出代码的简单方法。请参阅why does my JScript (windows script host) exit with 0 on an uncaught exception?

的解决方案

这是我们选择jscript而不是vbscript的首要原因(当我们 使用其中一个时!)

答案 4 :(得分:1)

您可以使用this article中描述的技术。 它要求您将脚本包装在VBScript类中。