windows 捕获 VBScript 中的任何错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2929715/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 14:32:36  来源:igfitidea点击:

capture any error in VBScript?

windowsvbscriptbatch-file

提问by JoelFan

I have a batch file that calls a VBScript (.vbs) program. After calling it, my batch script checks %errorlevel%to see if the .vbs program failed. I can signal failure with an exit code in the .vbs program with WScript.Quit(1).

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

However, I can only do that explicitly. If some unexpected run-time error happens, the .vbs quits with an error dialog box, however the exit code is zeroso my batch file thinks it suceeded! How can I change that behavior?

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

And if you are thinking of saying, use on error goto, don't bother... that syntax is available in regular VB, but not in VBScript.

如果您想说,使用on error goto,不要打扰...该语法在常规 VB 中可用,但在 VBScript 中不可用。

采纳答案by JoelFan

I thought of an out-of-the-box solution... Who says 0 has to mean success? VBScript sometimes returns a 0 return code for failures, so why not embrace that? Adopt 0 as (at least one possible) failure code and make up another number (e.g. 10) as the "success code".

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

At the end of the script, put WScript.Quit(10). That will only be hit if everything succeeded up to that point. Then instead of "if errorlevel 1" in the calling batch file, use "if %errorlevel% == 10"

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

回答by bacar

EDIT: Having tentatively (see caveats) proposed this, I am rapidly beginning to think that it is a very bad idea, but I leave it here for posterity. The most compelling reason to not use this comes from Eric Lippertat Microsoft, who worked on the design & implementation of VBScript. He states, in answer to another question: VBScript does not make any guarantee that terminators always run. This can mean that this sometimes does not return a non-0 exit code in the case of an unhandled error.

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

I think I personally will use a 'wrapper batch file that subtracts 1 from the cscript exit code' solution in future.

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



I like the solution linked to by fmunkert, but I think it requires you to put your code in a particular Class_Initalize, which is clumsy at best. I've devised a related solution that does not require this; you simply "Commit" a successful result at the end of your code; if it's not called, any exception causes the ExitCodeHandler's Class_Terminate instance to set a non-zero exit code.

我喜欢 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

Note that this idiom is used heavily in C++, where it is called RAII (Resource Acquisition Is Initialization)

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

You could of course embellish the class this to support other exit codes, error messages etc. You may want to put this in a common vbs file and use a mechanism for includes in vbscriptto share it.

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

Caveats

注意事项

I don't know the full details of downsides to calling WScript.Quit during stack unwinding due to an exeption in VBScript. I've disovered the following:

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

  1. Use with caution. I have come up with this and poked around with it when I saw fmunkert's linked suggestion, not used it extensively.
  2. If you explicitly call WScript.Quit(n), the ExitCodeHandler will replace nwith its own exit code. The workaround is to either always call ExitCodeHandler.Commit before calling WScript.Quit, or call the supplied ExitCodeHandler.Quitinstead which does it for you. However, relying on either of these methods may not always be practical/possible, and it is fairly non-idiomatic and may not be ovbious to maintainers.
  3. If any other object with a Class_Terminateis terminated (i.e. afterExitCodeHandler's Class_Terminatecalls WScript.Quit), you seem to get an error. You may get similar behaviour with any COM objects that are being destroyed. I don't know in what order VBScript destroys objects (or even if it's guaranteed), so I've asked about it in another question.
  1. 谨慎使用。当我看到 fmunkert 的链接建议时,我想出了这个并四处探索,但没有广泛使用它。
  2. 如果您显式调用 WScript.Quit( n),ExitCodeHandler 将用它自己的退出代码替换n。解决方法是在调用之前始终调用 ExitCodeHandler.Commit WScript.Quit,或者调用提供的ExitCodeHandler.Quit来代替它为您执行。然而,依赖这两种方法中的任何一种可能并不总是实用/可行,而且它相当不惯用,对维护者来说可能不是显而易见的。
  3. 如果任何其他带有 a 的对象Class_Terminate被终止(即ExitCodeHandlerClass_Terminate调用 WScript.Quit 之后),您似乎会收到一个错误。对于任何被销毁的 COM 对象,您可能会得到类似的行为。我不知道 VBScript 以什么顺序销毁对象(或者即使它是有保证的),所以我在另一个问题中询问了它

回答by bacar

You could, if it's an option, use jscript instead which has better support for exception handling, including an easy way to return a non-zero exit code on any exception. See the solution to why does my JScript (windows script host) exit with 0 on an uncaught exception?

如果可以选择,您可以改用 jscript,它对异常处理有更好的支持,包括一种在任何异常上返回非零退出代码的简单方法。请参阅有关为什么我的 JScript(Windows 脚本宿主)在未捕获的异常中以 0 退出的解决方案

This is the #1 reason we're choosing jscript over vbscript (when we haveto use one of the two!)

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

回答by Alex K.

As you say, all that's available is On Error Resume Next, so your forced to use the pattern:

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

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

回答by Alex K.

You might use the technique described in this article. It requires you to wrap your script inside a VBScript class.

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