захватить любую ошибку в VBScript? - PullRequest
6 голосов
/ 28 мая 2010

У меня есть пакетный файл, который вызывает программу VBScript (.vbs). После его вызова мой пакетный скрипт проверяет %errorlevel%, чтобы увидеть, произошла ли ошибка .vbs. Я могу сообщить о сбое с помощью кода выхода в программе .vbs с WScript.Quit(1).

Однако я могу сделать это только явно. Если происходит какая-то непредвиденная ошибка во время выполнения, .vbs закрывается с диалоговым окном ошибки, , однако код завершения равен нулю , поэтому мой пакетный файл считает, что это успешно! Как я могу изменить это поведение?

И если вы хотите сказать, используйте on error goto, не беспокойтесь ... этот синтаксис доступен в обычном VB, но не в VBScript.

Ответы [ 5 ]

5 голосов
/ 30 мая 2010

Я думал о готовом решении ... Кто сказал, что 0 означает успех? VBScript иногда возвращает 0 код возврата для сбоев, так почему бы не принять это? Принять 0 в качестве (по крайней мере одного возможного) кода ошибки и составить другое число (например, 10) в качестве «кода успеха».

В конце скрипта поместите WScript.Quit (10). Это будет ударить, только если все удалось до этого момента. Затем вместо «if errorlevel 1» в вызывающем пакетном файле используйте «if% errorlevel% == 10»

4 голосов
/ 15 сентября 2010

РЕДАКТИРОВАТЬ : Предварительно (см. Предостережения) предложили это, я быстро начинаю думать, что это очень плохая идея, но я оставляю ее здесь для потомков. Наиболее веская причина не использовать это от Эрика Липперта из Microsoft, который работал над дизайном и реализацией VBScript. Он заявляет, в ответ на другой вопрос : VBScript не дает никаких гарантий, что терминаторы всегда работают . Это может означать, что это иногда не возвращает код выхода, отличный от 0, в случае необработанной ошибки.

Я думаю, что лично я буду использовать «пакетный файл-обертку, который вычитает 1 из кода выхода cscript» в будущем.


Мне нравится решение, связанное с fmunkert, но я думаю, что оно требует, чтобы вы поместили свой код в определенный Class_Initalize, который в лучшем случае неуклюж. Я разработал соответствующее решение, которое не требует этого; вы просто «фиксируете» успешный результат в конце своего кода; если это не вызывается, любое исключение заставляет экземпляр Class_Terminate ExitCodeHandler установить ненулевой код завершения.

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 , чтобы поделиться им.

Предостережения

Я не знаю всех подробностей недостатков при вызове WScript.Quit во время разматывания стека из-за исключения в VBScript. Я обнаружил следующее:

  1. Используйте с осторожностью. Я придумал это и стал возиться с ним, когда увидел связанное предложение Фмункерта, а не использовал его широко.
  2. Если вы явно вызовете WScript.Quit ( n ), ExitCodeHandler заменит n своим собственным кодом выхода. Обходной путь должен либо всегда вызывать ExitCodeHandler.Commit перед вызовом WScript.Quit, либо вместо этого вызывать предоставленный ExitCodeHandler.Quit, который делает это за вас. Тем не менее, использование любого из этих методов не всегда может быть практичным / возможным, и это довольно не идиоматично и не может быть очевидным для сопровождающих.
  3. Если любой другой объект с Class_Terminate завершается (т. Е. после ExitCodeHandler's Class_Terminate вызывает WScript.Quit), вы, похоже, получаете сообщение об ошибке. Вы можете получить аналогичное поведение с любыми COM-объектами, которые уничтожаются. Я не знаю, в каком порядке VBScript уничтожает объекты (или даже если это гарантировано), поэтому я спросил об этом в другом вопросе .
2 голосов
/ 15 сентября 2010

Вы можете, если это вариант, использовать вместо этого jscript, который лучше поддерживает обработку исключений, включая простой способ возврата ненулевого кода завершения для любого исключения. Посмотрите решение для , почему мой JScript (хост скрипта Windows) завершает работу с 0 в необработанном исключении?

Это причина № 1, по которой мы выбираем jscript вместо vbscript (когда у нас есть для использования одного из двух!)

2 голосов
/ 28 мая 2010

Как вы говорите, все что доступно, это On Error Resume Next, поэтому вы вынуждены использовать шаблон:

On Error Resume Next
 ThingWithAChanceOfThrowingAnError ...
If (Err.number <> 0) then PrintErrorAndQuitWith1(Err.Description)
1 голос
/ 30 мая 2010

Вы можете использовать технику, описанную в этой статье . Это требует от вас обернуть ваш скрипт в класс VBScript.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...