Опубликован: 12.01.2008 | Уровень: специалист | Доступ: платный | ВУЗ: Мордовский государственный университет имени Н.П. Огарева
Лекция 7:

WSH как средство взаимодействия с внешними программами

< Лекция 6 || Лекция 7: 123 || Лекция 8 >

Запуск независимых консольных приложений и команд Windows

Для запуска независимых, т. е. работающих в отдельном адресном пространстве и использующих свою копию переменных среды, консольных приложений или внешних (представленных исполняемыми файлами на жестком диске) команд Windows используется метод Run объекта WshShell. При этом выполнение сценария можно приостановить до окончания работы запущенного приложения, а затем проанализировать код выхода этого приложения (для этого третий параметр метода Run должен равняться True ). Соответствующий пример сценария приведен в листинге 7.3.

'*******************************************************************
' Имя: RunConApp.vbs
' Язык: VBScript
' Описание: Запуск независимого консольного приложения и
'           определение его кода выхода
'*******************************************************************
Option Explicit

Dim WshShell, Code   ' Объявляем переменные
' Создаем объект WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
' Запускаем утилиту xcopy с ключом "/?" и ожидаем окончания ее работы
Code=WshShell.Run("xcopy /?",1,true)
' Печатаем полученный код возврата
WScript.Echo "Код возврата: ", Code
'*************  Конец *********************************************/
Листинг 7.3. Запуск независимого консольного приложения (VBScript)

Для выполнения внутренней команды Windows нужно запустить командный интерпретатор cmd.exe и передать ему в качестве параметра нужную команду. Для того чтобы при вызове командного интерпретатора не заботиться о полном пути к cmd.exe, нужно использовать переменную среды COMSPEC.

Замечание

Для получения значения переменной среды ее имя нужно окружить знаками % (например, %COMSPEC% ).

В листингах 7.4 приведен сценарий, в котором запускаются внутренние команды COPY /? (вызов встроенной справки для COPY ) и DIR %WINDIR% (вывод содержимого системного каталога Windows).

При этом окно, в котором выполняется команда COPY /?, не закрывается после завершения этой команды, т. к. при запуске командного интерпретатора был указан ключ /k, а информация, выводимая командой DIR %WINDIR%, перенаправляется в файл windir.txt, после чего командное окно закрывается, т. к. для командного интерпретатора в этом случае был указан ключ /c.

'*******************************************************************
' Имя: RunDOSCom.vbs
' Язык: VBScript
' Описание: Выполнение внутренних команд Windows
'*******************************************************************
Option Explicit

Dim WshShell, Code   ' Объявляем переменные
' Создаем объект WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
' Запускаем внутреннюю команду COPY
WshShell.Run "%COMSPEC% /k copy /?",1
' Запускаем внутреннюю команду DIR
WshShell.Run "%COMSPEC% /c dir %WINDIR% > windir.txt",1
'*************  Конец *********************************************/
Листинг 7.4. Запуск внутренней команды Windows (VBScript)

Запуск дочерних консольных приложений и команд DOS, использование их входных и выходных потоков

Консольное приложение или команду DOS можно запустить из сценария как дочернюю задачу, т. е. с теми же переменными среды, что у процесса-родителя. При этом информация, выводимая дочерним процессом, на экран дублироваться не будет, однако из родительского сценария можно считывать информацию из выходного потока и посылать данные во входной поток дочерней задачи (это напоминает конвейеризацию команд Windows, при которой данные выходного потока одной команды поступают во входной поток другой команды, например DIR | MORE ). Таким образом, из сценария можно запускать ту или иную утилиту командной строки и обрабатывать выводимые ей данные; иногда таким образом получить нужную информацию бывает проще и быстрее, чем при использовании объектной модели WSH или другого сервера автоматизации.

В качестве примера рассмотрим сценарий ExecConApp.vbs (листинг 7.5), который выводит на экран общее количество файлов в текущем каталоге и их имена. Данную информацию можно получить в сеансе командной строки с помощью команды DIR /B. Поэтому в сценарии мы запустим в качестве дочернего процесса внутреннюю команду DIR с ключом /B:

Set ObjExec=WshShell.Exec("%COMSPEC% /c dir /b")

и полностью считаем данные, появляющиеся в выходном потоке этого процесса. Для этого в цикле вызывается метод ReadAll, считывающий всю информацию, имеющуюся к тому времени в потоке StdOut объекта ObjExec, в переменную s:

IsBreak=False
Do While True  ' Бесконечный цикл
  ' Проверяем, достигнут ли конец выходного потока команды DIR
  If (Not ObjExec.StdOut.AtEndOfStream) Then
    ' Считываем полностью выходной поток команды DIR
    s=s+ObjExec.StdOut.ReadAll
  End If
  If IsBreak Then
    Exit Do  ' Выходим из цикла
  End If
  ' Проверяем, не завершилось ли выполнение DIR
  If ObjExec.Status=1 Then
    IsBreak=True
  Else
    WScript.Sleep 100 ' Приостанавливаем сценарий на 0,1 сек
  End If
Loop

Родительский и дочерний процессы работают асинхронно, поэтому пока команда DIR не перестанет выдавать данные, т. е. пока свойство Status объекта ObjExec не станет равным 1, выполнение сценария с помощью метода WScript.Sleep периодически приостанавливается на 0,1 секунды.

После того как считаны все данные из выходного потока команды DIR (свойство ObjExec.StdOut.AtEndOfStream равно True ), происходит выход из цикла и формирование из переменной s массива выведенных строк:

ArrS=Split(s,vbCrLf)  ' Формируем массив строк

Теперь остается подсчитать количество файлов в каталоге, которое на единицу меньше количества строк в массиве ArrS:

ColFiles=UBound(ArrS)  ' Количество файлов в текущем каталоге
и вывести нужные строки на экран:
WScript.StdOut.WriteLine "Всего файлов в текущем каталоге: " & ColFiles
For i=0 To ColFiles-1 
  WScript.StdOut.WriteLine ArrS(i)  ' Выводим строки на экран
Next
'*******************************************************************
' Имя: ExecConApp.vbs
' Язык: VbScript
' Описание: Запуск дочернего консольного приложения
'*******************************************************************
Option Explicit
' Объявляем переменные
Dim ObjExec,WshShell,s,IsBreak,ArrS,ColFiles,i
' Создаем объект WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
' Запускаем команду DIR
Set ObjExec=WshShell.Exec("%COMSPEC% /c dir /b")
s=""
IsBreak=False
Do While True  ' Бесконечный цикл
  ' Проверяем, достигнут ли конец выходного потока команды DIR
  If (Not ObjExec.StdOut.AtEndOfStream) Then
    ' Считываем полностью выходной поток команды DIR
    s=s+ObjExec.StdOut.ReadAll
  End If
  If IsBreak Then
    Exit Do  ' Выходим из цикла
  End If
  ' Проверяем, не завершилось ли выполнение DIR
  If ObjExec.Status=1 Then
    IsBreak=True
  Else
    WScript.Sleep 100 ' Приостанавливаем сценарий на 0,1 сек
  End If
Loop
ArrS=Split(s,vbCrLf)  ' Формируем массив строк
ColFiles=UBound(ArrS)  ' Количество файлов в текущем каталоге
WScript.StdOut.WriteLine "Всего файлов в текущем каталоге: " & ColFiles
For i=0 To ColFiles-1
  WScript.StdOut.WriteLine ArrS(i)  ' Выводим строки на экран
Next
'*************  Конец *********************************************
Листинг 7.5. Запуск дочернего консольного приложения (VBScript)
< Лекция 6 || Лекция 7: 123 || Лекция 8 >
Валентина Тюрина
Валентина Тюрина

Вопрос по лекции 7, где рассматривается взаимодействие со сторонними программами, в том числе эмуляция нажатия кнопок клавиатуры WshShell.SendKeys.

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

Можно вытащить информацию о объекте (кнопке) скажем с помощью AutoIt Info, или ориентироваться скажем на текст на кнопке..., но как на эту кнопку нажать? (без обхода по клавиатуре)

Александр Тагильцев
Александр Тагильцев

Где проводится профессиональная переподготовка "Системное администрирование Windows"? Что-то я не совсем понял как проводится обучение.