Определение и инициализация переменных

Боб Уэллс Консультант по программному обеспечению; специализируется на вопросах проектирования и реализации инфрастуктуры информационных систем, основанных на NT. Имеет сертификаты MCSE и MCT. С ним можно связаться по адресу bobwells@winntmag.com.
В статье, опубликованной в предыдущем номере журнала, подробно рассматривалась структура сценария. Я разделяю файлы сценариев на три секции: секция определений и инициализаций, тело сценария и секция определения подпрограмм. На этот раз стоит продолжить экскурс в основы сценариев и рассказать о секции инициализаций и определений. Для начала я изложу ряд основ VBScript, знание которых помогает облегчить переход к использованию Windows Scripting Host (WSH).

Основы VBScript

Как и в любом другом программирования, в VBScript есть несколько фундаментальных правил. Знание этих правил, на первый взгляд не таких уж и значительных, помогает сэкономить немало времени при отладке.

Первое правило состоит в том, что VBScript не чувствителен к регистру символов, которыми задаются идентификаторы. Например, если переменная определена как strTempFile, то к ней вполне можно обратиться и как к STRtEMPfILE. То же относится к операторам VBScript, именам функций и процедур. Тем не менее рекомендую выбрать для каждого идентификатора определенное сочетание регистров и в дальнейшем пользоваться только им.

Хотя VBScript и не чувствителен к регистру символов в идентификаторах, в некоторых ситуациях, например при сравнении двух символьных значений, за ним все же приходится следить. Это нужно делать и при обращении к идентификаторам из пространства имен Active Directory Service Interfaces (ADSI), т. е. для обозначения Lightweight Directory Access Protocol необходимо пользоваться именем LDAP, для обозначения Windows NT — WinNT, для NetWare 4.x — NDS, для NetWare 3.x — NWCOMPAT и т. д. Если не следить за регистром при использовании идентификаторов из пространства имен ADSI, то при попытке привязки к нему в ходе выполнения сценария может возникнуть ошибка. (Дополнительную информацию об использовании пространства имен ADSI можно найти в «Руководстве по Active Directory для программистов» («Active Directory Programmer?s Guide») по адресу: http://msdn. microsoft.com/developer/windows2000.)

Второе фундаментальное правило VBScript заключается в том, что для включения комментариев в текст сценария можно использовать апостроф (?) или оператор Rem. В сценарии demo.vbs, приведенном в Листинге 1, даны оба метода. Комментарии можно вставлять как самостоятельные строки или размещать в конце строк с инструкциями; нельзя лишь включать комментарий в конец строки, содержащей символ продления строки (_).

Листинг 1. Demo.vbs

? *
? demo.vbs
? *
? Секция определений и инициализаций
? *
Rem *** Директивы сценария ***
Option Explicit
On Error Resume Next
Rem *** Определения переменных ***
Dim objFileSystem, objShell, objLogFile, objTempFile
Dim arrStrings, intReturnCode
Dim strBuffer, strLogFile, strTempFile
Rem *** Задание констант ***
Const OpenFileForReading = 1
Rem *** Инициализация переменных ***
intReturnCode = 0
strBuffer	= ??
strLogFile	= ?c:? & Split(WScript.ScriptName, ?.?)(0) & ?.log?
strTempFile	= ?c:	emp.txt?
?НАЧАЛО БЛОКА А
(A)______________________________________________
arrStrings	= Array(?abcdefghijklmnopqrstuvwxyz?, _
	?ABCDEFGHIJKLMNOPQRSTUVWXYZ?, _
	?the quick brown fox jumps over the lazy dogs back?)
________________________________________________________	
?КОНЕЦ БЛОКА А
? Секция тела сценария
? *
?НАЧАЛО БЛОКА В
(B)_______________________________________________
? Использование конструкции If-Then-End If 
? для демонстрации работы директивы On Error Resume Next
If Err.Number Then
	WScript.Echo ?Bob?s Friendly Error Message? & vbNewLine & _
	?Error Number: ? & Err.Number & vbNewLine & _
	?Error Description: ? & Err.Description
	Err.Clear
End If
___________________________________________________________
?КОНЕЦ БЛОКА В
.
.
? *
? * конец demo.vbs

Правило третье: в тексте сценария может быть какое угодно количество пробелов или пустых строк. Добавление пробелов и пустых строк нередко может повысить читаемость кода. VBScript игнорирует пустые строки и пробелы между именами переменных и оператором присваивания (=).

Правило четвертое: хотя VBScript и не накладывает ограничений на длину строки, разбивка длинных строк может повысить читаемость текста сценария. Для разделения строки кода или управляющей конструкции можно воспользоваться символом продления. Я часто пользуюсь им при инициализации динамических массивов (см., например, блок А на Листинге 1) или для передачи длинной строки методу WScript.Echo, что несколько раз демонстрируется в теле сценария demo.vbs. Перед символом продления строки обязательно должен стоять пробел, иначе при обработке выражений некоторых типов может возникнуть ошибка.

Правило пятое гласит, что в одну строку можно включать несколько инструкций. В VBScript для этого следует использовать символ двоеточия (:). В строке

Dim strText: strText = ?WSH ROCKS!? : WScript.Echo strText

целых три инструкции: первая — Dim strText, вторая — strText — «WSH ROCKS!», третья — WScript.Echo strText. Я этой возможностью предпочитаю не пользоваться.

Правило шестое: каждая строка кода VBScript должна оканчиваться символом «новая строка». Он автоматически генерируется при нажатии на клавишу Enter. В VBScript не требуется вводить видимый символ окончания строки (;), используемый в JScript и Perl.

Правило седьмое и последнее касается идентификаторов VBScript (переменных, констант, имен функций и процедур). Идентификатор обязательно должен начинаться с буквы латинского алфавита; длина идентификатора не должна превышать 255 символов.

Секция определений и инициализаций

Секцию определений и инициализаций составляют директивы интерпретатора, определения переменных, задания констант и инициализация переменных. Все эти элементы (за исключением, быть может, инициализации) необязательны. Однако их использование упрощает отладку и сопровождение сценария.

Директивы VBScript. VBScript поддерживает две директивы интерпретатора, влияющие на поведение сценария во время исполнения: Option Explicit и On Error Resume Next.

Директива Option Explicit указывает, что все переменные перед использованием в сценарии будут определены при помощи оператора Dim. Это касается переменных, применяемых как в теле сценария, так и в пользовательских функциях и процедурах. Директива Option Explicit обязательно должна предшествовать всем остальным операторам в сценарии. Другими словами, она всегда находится в начале сценария. При обнаружении неопределенной переменной в ходе исполнения сценария с директивой Option Explicit интерпретатор выдаст сообщение об ошибке. Это помогает выявить опечатки и переменные с некорректной областью видимости. Область видимости определяет доступность переменной в различных частях сценария (функциях и процедурах).

ЭКРАН 1. Экран выбора опций при процедуре восстановления программы установки.

Директива On Error Resume Next управляет поведением сценария при обнаружении ошибок периода исполнения. Если сценарий не содержит этой директивы, то при возникновении ошибки WSH выводит диалог с соответствующим сообщением и прекращает исполнение. Соответствующий пример показан на Экране 1. Директива On Error Resume Next предписывает интерпретатору продолжать выполнение, невзирая на ошибку, а информация о ней помещается в объект VBScript.Err. Таким образом, эта директива позволяет отслеживать возникновение ошибок и программно обрабатывать их. Например, можно создать процедуру, выводящую на экран подробные сообщения об ошибках, или записывать сведения о них в журнальный файл. На Экране 2 показано диалоговое окно с информацией об ошибке.

ЭКРАН 2. Экран выбора опций при процедуре восстановления программы установки.

Использовать директиву On Error Resume Next для обработки ошибок очень полезно. Допустим, я закомментирую строку (т. е. добавлю в ее начало Rem), определяющую переменную intReturnCode в начале demo.vbs:

Rem Dim arrStrings, intReturnCode

Если я запущу свой сценарий, он выполнится до конца, но желаемый результат, возможно, достигнут не будет. Вместо стандартного сообщения WSH об ошибке периода исполнения сценарий выдаст изображенное на Экране 2 диалоговое окно с сообщением о неопределенной переменной. Конструкция If-Then-End If в блоке В Листинга 1 представляет собой примитивную подпрограмму обработки ошибок, отображающую в диалоговом окне значения свойств Number и Description объекта VBScript.Err. После того как пользователь нажмет на клавишу ОK в диалоговом окне с информацией об ошибке, выполнение сценария продолжится, потому что он содержит директиву On Error Resume Next. Если ее закомментировать, то вместо моего диалога при запуске сценария будет выведено окно WSH с сообщением об ошибке, показанное на Экране 1. Единственный довод в пользу отказа от директивы On Error Resume Next состоит в том, что информация в окне WSH Scripting Host Execution Error может быть более подробной, чем в свойствах объекта Err. В окне на Экране 1 выведены не только имя неопределенной переменной, но и номер строки, в которой возникли ошибки. Диалог, показанный на Экране 2, лишь сообщает о попытке использования неопределенной переменной.

Почему происходит ошибка? В demo.vbs я устанавливаю начальное значение переменной intReturnCode в 0 (инициализирую ее) в строке 19, за несколько строк до блока А. Но поскольку я поместил в начале сценария директиву Option Explicit и закомментировал строку определения intReturnCode, при попытке присвоить неопределенной переменной intReturnCode значение 0 возникает ошибка. Избежать ошибок, связанных с определением переменных, я могу, убрав директиву Option Explicit. Но все же лучше будет продекларировать неопределенную переменную (в данном случае убрать Rem из строки с определением):

Dim arrStrings, intReturnCode

В отличие от директивы Option Explicit, которая влияет на сценарий в целом, On Error Resume Next действует лишь на ту часть сценария, в которой задана директива (в теле сценария, функции или процедуре). Поскольку область видимости On Error Resume Next ограничена, можно точно задать участок сценария, на котором действует директива. (VBScript не поддерживает конструкцию On Error Goto Label, имеющуюся в Visual Basic.) Корректное использование директив On Error Resume Next и Option Explicit упрощает отладку, делает сценарий более понятным и надежным.

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

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

За определение переменных отвечает оператор Dim. В demo.vbs определения переменных идут сразу вслед за директивами интерпретатора, которые находятся в самом начале сценария. Основной тип данных VBScript — variant. Переменные типа variant — это переменные неопределенного типа. При определении переменной с помощью оператора Dim дополнительная информация о ее типе, как в Visual Basic, не требуется. VBScript поддерживает множество различных подтипов данных и функций преобразования данных из одного типа в другой, позволяющих произвольным образом изменять содержимое переменных типа variant. Дополнительную информацию о переменных VBScript можно найти в файле помощи VBScript, по адресу: http://msdn.microsoft.com/scripting/vbscript/download/vbsdoc.exe.

Инициализация переменных. Инициализация переменных — это присвоение им некоторого значения перед использованием. В demo.vbs я инициализирую несколько переменных, перед тем как задействовать их в теле сценария. Начальное значение переменной может быть простым — числом или строкой — либо составным, образованным из нескольких элементов.

К примеру, в разделе инициализации переменных demo.vbs сценарий присваивает переменной strLogFile значение, полученное при помощи конкатенации (объединения оператором VBScript &) трех подстрок. Первая (С:) и третья (.log) подстроки взяты в чистом виде. Вторая (средняя) подстрока извлекает значение свойства Wscript.ScriptName (в этом случае demo.vbs) и делит его на две части в месте нахождения точки (.). В своем примере я добавил индекс (0) в конец команды вызова функции Split, чтобы она вернула лишь первый из элементов (demo) массива, который обычно возвращает целиком. Конечный результат — имя журнального файла, идентичное имени сценария, но без расширения .vbs.

Задание констант. Константы — это именованные значения, не изменяющиеся на протяжении выполнения сценария. VBScript поддерживает константы двух типов — литерные и предопределенные. Литерные константы помогают сделать сценарий более понятным. Литерным константам в VBScript можно присваивать лишь скалярные значения. Интерпретатор не поддерживает константы, сконструированные из других констант или выражений.

В VBScript предусмотрены также предопределенные константы. В числе предопределенных констант, которые я использую чаще других, — константы, задающие управляющие (escape) последовательности. Например, в demo.vbs задействованы константы vbNewLine и vbTab.

VBScript не позволяет применять константы, заданные внешними объектами, например FileSystemObject или ADSI. Однако Microsoft планирует включить поддержку такой возможности в следующую версию WSH. В секции задания констант demo.vbs я определяю локальную константу OpenFileForReading, присваивая ей значение константы OpenFileForReading объекта FileSystemObject.

Поделитесь материалом с коллегами и друзьями