捕获VBScript中的任何错误?

Joe*_*Fan 6 windows vbscript batch-file

我有一个调用VBScript(.vbs)程序的批处理文件.调用它之后,我的批处理脚本会检查%errorlevel%.vbs程序是否失败.我可以通过.vbs程序中的退出代码发出故障信号WScript.Quit(1).

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

如果您正在考虑说,请使用on error goto,不要打扰...语法在常规VB中可用,但在VBScript中不可用.

Joe*_*Fan 5

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

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

  • "谁说0必须意味着成功?"......这是一个标准惯例,许多启动其他流程的工具都会假设它.有关更多详细信息,请参阅维基百科的[退出状态语义](http://en.wikipedia.org/wiki/Exit_status#Semantics).也就是说,VBscript在这方面已经被彻底打破了,鉴于有限的替代方案,它对于flout惯例是非常有吸引力的,_if_你知道什么会调用你的脚本_and_它就可以了.或者,您可以将脚本包装在一些内容中,例如,从退出代码中减去1.只要你没有在vbscript中写出所说的包装器; ^] (2认同)

bac*_*car 5

编辑:暂时(参见注意事项)提出这一点后,我很快开始认为这是一个非常糟糕的主意,但我将其留在这里供后代使用。不使用它的最令人信服的理由来自Microsoft 的Eric Lippert,他致力于 VBScript 的设计和实现。他在回答另一个问题时指出: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
Run Code Online (Sandbox Code Playgroud)

请注意,这个习惯用法在 C++ 中大量使用,称为RAII(资源获取即初始化)

当然,您可以修饰该类以支持其他退出代码、错误消息等。您可能希望将其放入公共 vbs 文件中,并使用包含在 vbscript 中的机制来共享它。

注意事项

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

  1. 谨慎使用。当我看到 fmunkert 的链接建议时,我想出了这个并进行了研究,但没有广泛使用它。
  2. 如果显式调用 WScript.Quit( n ),ExitCodeHandler 会将n替换为其自己的退出代码。解决方法是要么始终在调用之前调用 ExitCodeHandler.Commit WScript.Quit,要么调用提供的方法ExitCodeHandler.Quit来为您完成此操作。然而,依赖这两种方法中的任何一种可能并不总是实用/可能的,而且它相当不惯用,并且对于维护者来说可能并不明显。
  3. 如果任何其他带有 a 的对象Class_Terminate被终止(即在ExitCodeHandler调用 WScript.Quit之后Class_Terminate),您似乎会收到错误。对于任何被销毁的 COM 对象,您可能会遇到类似的行为。我不知道 VBScript 以什么顺序销毁对象(或者即使它是有保证的),所以我在另一个问题中询问了它