捕获VBScript中的任何错误?

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

但是,我只能明确地做到这一点。 如果发生意外的运行时错误,.vbs会退出,并出现错误对话框, 但退出代码为零,所以我的batch file认为它已经成功! 我如何改变这种行为?

如果你想说,使用on error goto ,不要打扰…该语法是在常规的VB中可用,而不是在VBScript中。

Solutions Collecting From Web of "捕获VBScript中的任何错误?"

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

在脚本的末尾,把WScript.Quit(10)。 如果一切都成功的话,那只会受到打击。 然后在调用的批处理文件中使用“if%errorlevel%== 10”代替“if errorlevel 1”

编辑 :暂时(见警告)提出这一点,我很快就开始认为这是一个非常糟糕的主意,但我留在这里为后代。 不使用这个的最有说服力的理由来自Microsoft的Eric Lippert ,他从事VBScript的设计和实现。 他在回答另一个问题时指出: VBScript不保证终止程序总是运行 这可能意味着这在有未处理的错误的情况下有时不会返回非0退出代码。

我想我个人将来会使用'包装器批处理文件,从cscript退出代码'减去1。


我喜欢fmunkert链接到的解决方案,但是我认为它需要你把你的代码放在一个特定的Class_Initalize中,而这个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(资源获取是初始化)

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

注意事项

我不知道由于在VBScript中的一个exeption在堆栈展开期间调用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以什么顺序破坏对象(或者即使有保证),所以我在另一个问题上提出了这个问题 。

正如你所说,所有可用的是On Error Resume Next ,所以你不得不使用的模式:

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

你可以,如果它是一个选项,而是使用jscript而不是更好的异常处理支持,包括一个简单的方法来返回任何异常的非零退出代码。 看到为什么我的JScript(Windows脚本宿主)以未捕获的异常退出0?

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

您可以使用本文中描述的技术。 它要求你将脚本包装在一个VBScript类中。