Глава 3.13. Дополнительные возможности JScript

В этой главе приведены описания нестандартных возможностей языка Microsoft JScript, реализованных в обозревателе Internet Explorer, а именно:

Мы не приводим описания объекта VBArray, используемого для доступа к массивам Visual Basic, т. к. наш справочник не содержит раздела, посвященного языку VBScript.

3.13.1. Управляющие элементы ActiveX

3.13.1.1. Общее описание

Основные дополнения к языку JavaScript, сделанные корпорацией Microsoft, связаны с использованием управляющих элементов ActiveX. Эти элементы представляют собой динамические библиотеки, созданные в соответствии со стандартом COM. COM (Component Object Model) — это стандарт создания программных компонентов, рассмотрение которого выходит за рамки нашего справочника. Для наших целей вполне достаточно воспринимать элементы ActiveX как черный ящик, выполняющий определенные действия по запросу вызвавшей его программы.

Появление элементов ActiveX было порождено стремлением Microsoft создать технологию, которая могла бы успешно конкурировать с подключаемыми модулями обозревателей Netscape. Следует признать, что задача была решена исключительно удачно, т. к. в результате появился стандарт разработки платформо-зависимых программных компонентов, реализующих платформо-независимые протоколы и архитектуры.

Все элементы ActiveX при установке в системе Windows регистрируются в ее регистре. При этом в качестве уникального ключа используется GUID данного элемента, т. е. его уникальный 64-разрядный шестнадцатеричный номер. Для доступа к элементу ActiveX по его GUID в HTML-документе используется элемент OBJECT, например:

<OBJECT style="left: 0px; top: 0px"
  classid="clsid:8E27C92B-1264-101C-8A2F-040224009C02">
    <PARAM NAME="_Version" VALUE="524288">
    <PARAM NAME="_ExtentX" VALUE="7620">
    <PARAM NAME="_ExtentY" VALUE="5080">
    <PARAM NAME="_StockProps" VALUE="1">
    <PARAM NAME="BackColor" VALUE="-2147483633">
    <PARAM NAME="Year" VALUE="2000">
    <PARAM NAME="Month" VALUE="10">
    <PARAM NAME="Day" VALUE="22">
    <PARAM NAME="DayLength" VALUE="1">
    <PARAM NAME="MonthLength" VALUE="2">
    <PARAM NAME="DayFontColor" VALUE="0">
    <PARAM NAME="FirstDay" VALUE="2">
    <PARAM NAME="GridCellEffect" VALUE="1">
    <PARAM NAME="GridFontColor" VALUE="10485760">
    <PARAM NAME="GridLinesColor" VALUE="-2147483632">
    <PARAM NAME="ShowDateSelectors" VALUE="-1">
    <PARAM NAME="ShowDays" VALUE="-1">
    <PARAM NAME="ShowHorizontalGrid" VALUE="-1">
    <PARAM NAME="ShowTitle" VALUE="-1">
    <PARAM NAME="ShowVerticalGrid" VALUE="-1">
    <PARAM NAME="TitleFontColor" VALUE="10485760">
    <PARAM NAME="ValueIsNull" VALUE="0">
</OBJECT>

Этот фрагмент HTML-документа содержит управляющий элемент ActiveX "Календарь" и будет отображаться обозревателем примерно так:

Отображение элемента Календарь

Исполняющая система JScript дает нам более гибкие возможности запуска элементов ActiveX, которые описаны ниже.

3.13.1.2. Объект ActiveXObject

Объект ActiveXObject используется для запуска объектов ActiveX. Он создается конструктором

new ActiveXObject("сервер.класс" [,"адрес"?])

Здесь сервер — имя COM-сервера, класс — имя класса создаваемого объекта, адрес — необязательное имя сетевого сервера, на котором должен быть создан заданный объект (может быть доменным именем или IP-адресом). Создание объекта на удаленном сервере действующими версиями JScirpt пока не поддерживается, т. е. аргумент адрес при вызове данного конструктора игнорируется.

После создания объекта ActiveX (т. е. после запуска соответствующей программы) мы можем обращаться к его методам и свойствам, используя стандартный синтаксис языка JavaScript. Встроенных свойств и методов этот объект не имеет.

Пример: если на компьютере-клиенте установлен Microsoft Word 7.0, то следующий сценарий его запустит, откроет документ Mydoc.doc, сохранит этот документ в текстовом формате и завершит работу MS Word.

var word = new ActiveXObject("Word.Application"); // запускает MS Word
word.Documents.Open("Mydoc.doc");		  // открывает документ
word.ActiveDocument.SaveAs("Mydoc.txt", 4);	  // 4 = текстовый формат DOS
word.Quit();					  // завершает работу MS Word

Примечания.

  1. Следует помнить, что после запуска объекта ActiveX он остается активным до закрытия окна обозревателя, из которого он был вызван. JScript не содержит стандартного средства для завершения работы этого объекта. Если мы хотим, чтобы объект прекратил работу ранее завершения работы нашего сценария, то должны вызвать соответствующий метод данного объекта (в приведенном примере это метод Quit).
  2. Любопытно, что операция typeof возвращает для свойств и методов объектов ActiveX нестандартное значение "unknown" (видимо из-за того, что все объекты ActiveX являются наследниками COM-интерфейса IUnknown).

WDH+ Примеры использования элементов ActiveX см. в WDH+: TreeView на Веб-странице.

3.13.1.3. Функция GetObject

Функция GetObject возвращает ссылку на COM-объект, содержащийся в заданном файле. Она имеет вид

GetObject(["имя_файла"][,"сервер.класс"?])

Здесь имя_файла — спецификация файла, сервер — имя COM-сервера, класс — имя класса объектов. Если имя_файла опущено, то задание второго аргумента обязательно, в противном случае оно может быть опущено.

При вызове этой функции запускается приложение, ассоциированное с заданной спецификацией файла (перечень таких ассоциаций хранится в системном регистре Windows). Если имя_файла — это пустая строка "", то создается новый экземпляр объекта заданного типа. Если имя_файла опущено, то возвращается ссылка на объект данного типа, который активен в данный момент. Если такого объекта нет, то генерируется ошибка.

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

Так, например, программа автоматизации проектирования может хранить в файле чертежей несколько слоев. Для активации второго слоя в файле чертежа с именем MyCad.cad мы можем использовать строку

var layerObj = GetObject("MyCad.cad!Layer2");

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

var myObj = GetObject("SAMPLE.DRW", "FIGMENT.DRAWING");

В этом примере FIGMENT — имя программы, а DRAWING — один из классов объектов, которые она поддерживает.

После активации объекта мы можем обращаться к его методам и свойствам, используя стандартный синтаксис языка JavaScript. Встроенных свойств и методов этот объект не имеет.

Функцией GetObject следует пользоваться в тех случаях, когда приложение, создающее экземпляры объектов данного класса, уже активно или когда мы хотим не только запустить приложение, но и загрузить в него файл, содержащий нужный нам объект. В остальных случаях используйте объект ActiveXObject.

Если объект зарегистрирован как существующий в единственном экземпляре (например Word.Basic в Microsoft Word 7.0), то GetObject всегда возвращает ссылку на этот единственный экземпляр объекта, будучи вызвана с пустой строкой в качестве имени файла, и генерирует ошибку, если имя_файла опущено.

Примечание. Приведенное описание функции GetObject и примеры ее использования позаимствованы из документации Microsoft. Дело в том, что автор не смог найти ни одного разумного применения этой функции в клиентской среде. Более того, по сообщению разработчиков, в обозревателях Interent Explorer ее применение запрещено "в целях безопасности" (см. Q239470 Внешняя ссылка).

3.13.2. Коллекции: объект Enumerator

Объект Enumerator используется для просмотра элементов коллекций. Коллекции — это списки объектов, реализованные в исполняющей системе JScript, но непосредственно не доступные пользователю. В частности, мы не можем добраться до их элементов ни с помощью индексов, ни с помощью оператора for…in. Вместо этого мы должны создать для коллекции объект Enumerator, а затем последовательно перемещать его указатель от текущего элемента коллекции к следующему. Объект создается конструктором

new Enumerator(коллекция)

где коллекция — любой объект, являющийся коллекцией. При создании объекта его указатель устанавливается на первый элемент коллекции.

Следующий сценарий позаимствован из документации к JScript и демонстрирует использование данного объекта:

function showDrives()
{
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  var e = new Enumerator(fso.Drives);
  var s = "";
  var name;
  for (e.moveFirst(); !e.atEnd(); e.moveNext()) {	// просмотр всех дисков компьютера
    var x = e.item();
    if (x.DriveType == 3)	// сетевой диск?
      name = x.ShareName;
    else if (x.IsReady)
      name = x.VolumeName;
    else
      name = "[Диск не готов]";
    s +=  x.DriveLetter + ": " + name + "<br>";
  }
  return(s);
}

document.write(showDrives());

Объект Enumerator не имеет свойств; его методы описаны ниже.

Методы объекта Enumerator
Метод Описание
atEnd Проверяет, достигнут ли конец коллекции.
item Возвращает текущий элемент коллекции.
moveFirst Делает текущим первый элемент коллекции.
moveNext Делает текущим следующий элемент коллекции.

Метод atEnd

Синтаксис: объект.atEnd()
Результат: логическое значение

Метод atEnd возвращает true, если текущий элемент коллекции является последним в ней, и false в противном случае. См. приведенный выше пример.

Метод item

Синтаксис: объект.item()
Результат: объект

Метод item возвращает текущий элемент коллекции. Если коллекция пуста или текущий элемент не определен, то возвращается значение undefined. См. приведенный выше пример.

Метод moveFirst

Синтаксис: объект.moveFirst()

Метод moveFirst перемещает указатель на первый элемент коллекции. См. приведенный выше пример.

Метод moveNext

Синтаксис: объект.moveNext()

Метод moveNext перемещает указатель на следующий элемент коллекции. См. приведенный выше пример.

3.13.3. Информация о исполняющей системе

Описанные ниже функции возвращают различную информацию о исполняющей системе сценариев. Их применение можно проиллюстрировать следующим примером:

function GetScriptEngineInfo() {
  var s = "";
  s += ScriptEngine() + " ";
  s += ScriptEngineMajorVersion() + ".";
  s += ScriptEngineMinorVersion() + ".";
  s += ScriptEngineBuildVersion();
  return s;
}

document.write(GetScriptEngineInfo());

В результате выполнения этого сценария на экран обозревателя будет выведен примерно такой текст: JScript 5.5.5207.

3.13.3.1. Функция ScriptEngine

Синтаксис: ScriptEngine()
Результат: строковое значение

Функция ScriptEngine возвращает одну из следующих строк, указывающую на текущий сценарный язык:

"JScript" Microsoft JScript
"VBA" Microsoft Visual Basic for Applications
"VBScript" Microsoft Visual Basic Scripting Edition

3.13.3.2. Функция ScriptEngineBuildVersion

Синтаксис: ScriptEngineBuildVersion()
Результат: строковое значение

Функция ScriptEngineBuildVersion возвращает строку, содержащую номер сборки (build version) исполняющей системы сценариев.

3.13.3.3. Функция ScriptEngineMajorVersion

Синтаксис: ScriptEngineMajorVersion()
Результат: строковое значение

Функция ScriptEngineMajorVersion возвращает строку, содержащую номер версии исполняющей системы сценариев.

3.13.3.4. Функция ScriptEngineMinorVersion

Синтаксис: ScriptEngineMinorVersion()
Результат: строковое значение

Функция ScriptEngineMinorVersion возвращает строку, содержащую номер подверсии исполняющей системы сценариев.

3.13.4. Условная компиляция

3.13.4.1. Понятие условной компиляции

Начиная с Internet Explorer 4.0, язык JScript поддерживает условную компиляцию сценариев. Она была введена в JScript для того, чтобы одновременно обеспечить и использование новых возможностей языка, и совместимость со старыми версиями обозревателей. Типичными примерами использования условной компиляции являются добавление в сценарий отладочного кода и трассировка исполнения сценария.

Условная компиляция включается директивой @cc_on или директивами @if или @set.

Директивы условной компиляции всегда следует помещать внутрь комментариев с тем, чтобы обозреватели, которые не поддерживают условную компиляцию (например, Netscape Navigator), их игнорировали. Приведем пример:

/*@cc_on @*/
/*@if (@_jscript_version >= 4)
   alert("JScript версии 4 или выше");
   @else @*/
   alert("Ваш JScript устарел.");
/*@end @*/

В этом примере использованы комментарии специального вида, которые используются только после директивы @cc_on. Обозреватели, которые не поддерживают условную компиляцию, увидят здесь только строку alert("Ваш JScript устарел.") и исполнят ее.

3.13.4.2. Переменные условной компиляции

В директивах условной компиляции могут использоваться предопределенные переменные, перечисленные в приведенной ниже таблице. Если значение переменной отлично от true, то она не определена и ведет себя как NaN.

Переменные условной компиляции
Переменная Описание
@_win32 true при выполнении в системе Win32.
@_win16 true при выполнении в системе Win16.
@_mac true при выполнении в системе Apple Macintosh.
@_alpha true при выполнении на процессоре DEC Alpha.
@_x86 true при выполнении на процессоре Intel.
@_mc680x0 true при выполнении на процессоре Motorola 680x0.
@_PowerPC true при выполнении на процессоре Motorola PowerPC.
@_jscript Всегда true.
@_jscript_build Номер сборки JScript.
@_jscript_version Номер версии JScript в формате m.n.

3.13.4.3. Директива @cc_on

Синтаксис: @cc_on

Директива @cc_on включает условную компиляцию. Пример ее использования приведен выше.

Альтернативный способом включения условной компиляции является использование директив @if или @set, не заключенных в комментарий.

3.13.4.4. Директива @if

Синтаксис:
@if (условие1)
  текст1
@elif (условие2)
  текст2
@else
  текст3
@end
Аргументы: условие1, условие2 — логические выражения
           текст1, текст2, текст3 — любой текст JScript

Директива @if выполняет заданный фрагмент кода в зависимости от значения выражения. Если условие1 истинно, то выполняется текст1. Если условие1 ложно, присутствует необязательная директива @elif и условие2 истинно, то выполняется текст2. В противном случае, если присутствует необязательная директива @else, то выполняется текст3; если ее нет, то управление передается следующему оператору. Данная директива может содержать несколько ветвей @elif, но все они должны предшествовать ветви @else. Пример ее использования:

@if (@_win32)
  alert("Работаем в Windows NT/95/98")
@else
  alert("Неизвестная операционная система!");

3.13.4.5. Директива @set

Синтаксис: @set @перем = значение
Аргументы: перем — переменная условной компиляции
           значение — числовое или логическое выражение

Директива @set создает переменные условной компиляции. Имена таких переменных имеют синтаксис переменных JavaScript, но должны начинаться с символа "@". Значение, которое присваивается переменной, может быть любым выражением JavaScript (возможно с использованием ранее определенных переменных условной компиляции), которое возвращает числовое или логическое значение. Примеры:

@set @var1 = 1
@set @var2 = (@var1 + 1) * 10;
@set @var3 = @_jscript_version

Если переменная используется до ее определения, то она имеет значение NaN. Поскольку это единственное значение. которое не равно самому себе, то проверку определенности значения переменной следует делать так:

@if (@myVar != @myVar) …