До появления системы Windows разработка многих программ следовала в строгом соответствии с процедурным подходом. То есть мы запускали программу и ждали, когда она закончит выполняться. По завершении ее работы на экране снова появлялось приглашение командной строки, и можно было запускать другую программу. С появлением Windows в дизайне программ стала преобладать другая парадигма: событийно-управляемое программирование. Всякий раз, когда мы интерактивно взаимодействуем с приложением, происходит некоторое событие. Например, если мы щелкаем мышью по командной кнопке, имеющейся в какой-либо форме или на Web-странице, то, говоря языком программирования, мы тем самым генерируем для данной кнопки событие Click. Для его обработки программист должен написать соответствующую процедуру. Если такая процедура отсутствует, то система Windows просто проигнорирует это событие.

Данная концепция работы с событиями может использоваться и в сценариях. Иначе говоря, мы можем писать событийно-управляемые сценарии. Прежде чем я расскажу о том, как создавать такие сценарии, следует разобраться в том, как возникают события и познакомиться с терминологией, используемой для описания этого процесса.

Источник события подает сигнал о том, что оно произошло. Широковещательное распространение этого сигнала называется генерацией события. События могут генерироваться любым объектом, который в этом случае называют источником события (event firer или event sender). Реакция на событие формируется в приемнике (event receiver), а сам этот процесс называется "перехватом" (trapping) или "приемом" (sinking) события. Приемниками событий (их также часто называют обработчиками (handler или sink)) обычно являются некоторые процедуры. Итак, источник порождает событие, а приемник перехватывает его и выполняет соответствующие действия.

В общем случае, те события, с которыми мы можем работать в сценариях, можно разделить на четыре типа:
·        события, порождаемые элементами управления ActiveX
·        события, порождаемые ошибками
·        события, порождаемые специальным программным кодом, реализованным с помощью Windows Script Components (WSC)
·        события, порождаемые специальным программным кодом, реализованным с помощью Windows Management Instrumentation (WMI)

Ниже будут рассмотрены первые три типа событий, порождаемые ActiveX, ошибками и WSC. События WMI будут обсуждаться в другой статье.

События ActiveX

Если вы разрабатываете сценарии, то наверняка знаете, как использовать элементы управления Active X. Обычно эти элементы имеются у объектов, у которых есть свои методы, свойства и события. Если элементы управления поддерживают автоматизацию, то мы можем взаимодействовать со всеми или частью этих методов, свойств и событий через сценарии. В частности, автоматизацию поддерживает объект InternetExplorer.Application – корневой объект приложения Microsoft Internet Explorer (IE), поэтому мы можем использовать его в сценариях, управляемых событиями.

В объекте WScript, который является корневым в иерархии объектной модели Windows Script Host (WSH), имеется возможность перехватывать события, порождаемые элементами управления Active X. Данный объект доступен из любого сценария WSH, поэтому для того чтобы обращаться к его методам и свойствам, нет необходимости специально его создавать.

Чтобы создать экземпляр объекта Active X, используется метод CreateObject объекта WScript. Причина, по которой следует использовать именно метод CreateObject объекта WScript, а не функцию CreateObject, имеющуюся в VBScript, можно выразить, в частности, так: "Принципиальная разница между методом CreateObject и функцией CreateObject состоит в их дополнительных вторых параметрах (соответственно, strPrefix и location). Второй параметр метода CreateObject поддерживает перехват событий от объектов автоматизации и источников событий. Что касается второго параметра функции CreateObject, то он используется для создания объектов на удаленных компьютерах".

Все, что требуется для создания обработчика событий – это второй параметр метода CreateObject. Например, при помощи команды

WScript.CreateObject("InternetExplorer.Application","IE_")

создается объект InternetExplorer.Application и организуется обработка событий, генерируемых этим объектом. Второй параметр (IE_) определяет префикс, который мы должны использовать в имени процедуры, являющейся обработчиком событий. Имя обработчика должно начинаться с этого префикса (обычно представляет собой сокращенное название объекта), за которым следует имя обрабатываемого события. Например, имя обработчика для события onQuit объекта IE может выглядеть как IE_onQuit.

В принципе, данное соглашение об именовании не является строго обязательным. Некоторые разработчики предпочитают использовать в качестве префикса не имя объекта, а обозначение SINK_. Но все это хорошо до тех пор, пока вам не потребуется отслеживать в сценарии события от двух или более объектов. В этом случае придется использовать имена SINK1_, SINK2_ и т.д., что, в конечном счете, может привести к путанице.

Как отмечалось выше, обработчиками событий являются процедуры, поэтому для их создания используется предложение Sub языка VBScript. Например, создание процедуры, обрабатывающей событие onQuit приложения IE может быть реализовано следующим образом:

Sub IE_onQuit
   ' Здесь размещаются команды, выполняемые процедурой.
End Sub

Какие именно действия должны выполняться в ответ на то или иное событие, зависит от события, а также от того результата, который вы хотите получить. Рассмотрим представленный в Листинге 1 пример сценария SimpleEventSink.vbs. Он начинается с предложения Option Explicit и объявления переменной objIE. Далее создается экземпляр объекта InternetExplorer.Application, для которого формируется ссылка на переменную objIE. Поскольку данный объект будет перехватывать события, для обработки события onQuit создана процедура IE_onQuit (см. фрагмент с меткой A Листинга 1). Обработчик IE_onQuit после приема события выполняет два действия. Сначала он выводит сообщение о том, что событие произошло. Далее, используя метод Quit объекта WScript, он принудительно завершает сценарий. Завершение сценария реализовано в обработчике события по той причине, что в основном теле сценария вызывается окно IE в видимом режиме и запускается бесконечный цикл, ожидающий приема события. Таким образом, если обработчик события не будет завершать сценарий, его выполнение не закончится никогда.

Внутри бесконечного цикла с помощью метода Sleep объекта WScript выполнение сценария приостанавливается на 5 миллисекунд (5 мс). Если вы используете бесконечный цикл, подобный этому, то обязательно добавляйте в него строку Sleep. Если этого не сделать, процесс WSH займет более 90% ресурсов процессора, в результате чего завершить этот процесс вы сможете только с помощью диспетчера задач Task Manager Windows.

Также следует убедиться в том, что при обработке события onQuit останавливается процесс закрытия IE. При приеме какого-либо события может возникнуть ситуация, когда источник события ожидает результатов. Данная задержка обычно не приводит к проблемам, но если ваша программа входит в обобщенный процесс, то это может предотвратить закрытие IE.

События, порождаемые ошибками

В сценариях WSH перехват событий, связанных с ошибками, и формирование отклика на них выполняются автоматически. Допустим, вы написали сценарий из четырех строк, третья строка которого выдает ошибку. Когда выполнение сценария доходит до третьей строки, WSH генерирует событие ошибки. Далее WSH автоматически перехватывает это событие, завершает выполнение сценария и стандартным образом выводит подробное описание ошибки в диалоговое окно или в командную строку, в зависимости от того, как был запущен сценарий (через wscript.exe или cscript.exe, соответственно).

Вы можете принудительно отключить обработку ошибок в сценарии WSH, для чего в него включается предложение On Error Resume Next. Если используется эта инструкция и WSH обнаруживает ошибку, то, по возможности, он будет продолжать дальнейшее выполнение сценария. Иначе говоря, при этом выполнение сценария не прекращается. Обычно инструкция On Error Resume Next размещается в начале сценария, хотя, в принципе, она может включаться в текст в любом месте.

Если используется инструкция On Error Resume Next, тогда вам следует предусмотреть в своем сценарии какие-либо альтернативные методы проверки ошибок. В одном из примеров для перехвата и обработки ошибок периода выполнения применяется процедура CheckError. Она использует возможности объекта Err, имеющегося в VBScript, который возвращает информацию об ошибках периода выполнения. Этот внутренний объект имеет глобальную область действия, поэтому специально создавать его экземпляр внутри сценария не требуется. А поскольку мы можем задавать свойства объекта Err, следовательно, в сценариях можно генерировать ошибки, которые могут быть автоматически обработаны либо WSH, либо другим обработчиком ошибок (например, таким как процедура CheckError).

Пример того, как можно работать с объектом Err, показан в Листинге 2 (сценарий SimpleRaiseError.vbs). Если вы хотите генерировать какие-либо свои ошибки, тогда нужно использовать для них шестнадцатеричные значения, превышающие 80040000. Поэтому в сценарии SimpleRaiseError.vbs сначала объявляется константа vbObjectError, ей присваивается шестнадцатеричное значение 80040000, которое затем увеличивается на 1.

Далее объект Err очищается с помощью метода Clear, таким образом, исключается возможность существования ошибок, появлявшихся ранее. Вообще говоря, очистка существующих параметров ошибок перед генерацией новой ошибки является хорошей практикой, поскольку в противном случае объект Err может содержать данные, сохранившиеся в нем от предыдущей ошибки. Когда WSH обнаруживает строку, содержащую метод Clear или предложение On Error Resume Next, он сбрасывает свойства объекта Err в 0 (т.е. присваивает им пустые значения).

После очистки параметров ошибки я использую метод Raise объекта Err с тремя из пяти возможных параметров. Первый параметр представляет собой номер ошибки, который я предполагаю использовать, в данном случае это число 80040001. Второй параметр определяет источник в объекте или сценарии, являющийся причиной возникновения ошибки. Третий параметр - это строка, содержащая краткое описание ошибки. Два оставшиеся параметра, которые я не стал использовать – параметры helpfile и helpcontext – применяются для задания указателей на файл подсказки Help и на раздел в этом файле, соответственно. Эти параметры вы вряд ли будете использовать в сценариях. Завершается сценарий выводом на экран информации, принятой объектом Err, для чего используется функция MsgBox.

Чтобы получить более подробную информацию о методах обработки ошибок, зайдите на страницу TechNet Script Center (http://www.microsoft.com/technet/scriptcenter/default.asp). Затем в каталоге, находящемся слева, последовательно перейдите по ссылкам Scripting Guides, Windows 2000 Scripting Guide, Scripting Concepts and Technologies for System Administration, VBScript Primer, VBScript Reference, Error Handling.

События WSC

Компоненты управления, поддерживающие автоматизацию, можно создавать самостоятельно – причем для этого не надо быть программистом или иметь какое-либо инструментальное средство для разработки программ. В качестве альтернативы программированию вы можете создавать собственные компоненты управления с поддержкой автоматизации и затем регистрировать их для дальнейшего использования. Аналогично компонентам управления Active X, подобные компоненты могут иметь свои методы, свойства и события. Они называются компонентами WSC.

Более подробную информацию о WSC можно получить из Microsoft Developer Network (MSDN) Library (http://msdn.microsoft.com/library). Для этого в левой части окна, где отображаются каталоги, последовательно перейдите по следующим ссылкам: Web Development, Scripting, Documentation, Windows Script Technologies, Windows Script Components.

Жизнь, полная событий

Надеюсь, что данная публикация послужит для вас хорошим введением в основы работы с событиями в WSH. В следующей статье я расскажу, как создавать более сложные сценарии, управляемые событиями, в том числе сценарии, которые выполняют перехват событий, порождаемых ошибками сценариев, выполняемых удаленно, а также сценарии, осуществляющие синхронный и асинхронный мониторинг событий с использованием WMI.

 ЛИСТИНГ 1. SimpleEventSink.vbs

Option Explicit
Dim objIE
Set objIE = WScript.CreateObject( _
      "InternetExplorer.Application", "IE_")
objIE.Visible = True
While True
      WScript.Sleep 5
Wend
' BEGIN CALLOUT A
Sub IE_onQuit
      WScript.Echo "Событие перехвачено"
End Sub
' END CALLOUT A


Листинг 2. SimpleRaiseError.vbs

On Error Resume Next
Const vbObjectError = &H80040000
Err.Clear
Err.Raise vbObjectError + 1, "error source", "error description"
MsgBox "Номер: " & Err.Number _
      & vbCrLf & "Источник: " & Err.Source _
      & vbCrLf & "Описание: " & Err.Description