Обучаем сценарии печатать файлыt Notepad, Word, Excel, and HTML

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

Простейший путь

Самый простой способ организации печати из сценариев состоит в том, чтобы использовать возможности печати программы Notepad. Если Notepad запускается с ключом /p, то соответствующий файл будет выведен на принтер, подключенный по умолчанию к системе. Например, приведенная ниже команда обеспечивает вывод файла mylog.txt на подключенный по умолчанию принтер:

Notepad /p c:mylog.txt

На Листинге 1 приведен фрагмент кода VBScript, использующего данную команду. Здесь следует отметить, что данный фрагмент будет работать нормально при условии, что в переменной среды PATH вашей системы содержится описание пути к программе Notepad. В противном случае этот путь необходимо полностью указать в команде.

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

Использование метода CopyFile и имен UNC

При реализации задач, выполняющихся в полностью автоматическом режиме, можно предусмотреть в сценарии передачу созданного им файла, в тот порт компьютера, который используется системой для связи с соответствующим принтером. На Листинге 2 показан пример того, как с помощью метода CopyFile объекта FileSystemObject соответствующий файл копируется на принтер, путь к которому описывается с помощью универсального соглашения об именовании - Universal Naming Convention (UNC). Для того чтобы использовать данный фрагмент для ваших конкретных задач отредактируйте в нем переменные strFilePath и strPrinterUNC так, чтобы они содержали, соответственно, имя предназначенного для печати файла и описание пути к требуемому сетевому принтеру. Не забудьте проверить, правильно ли отформатирован файл, предназначенный для печати, поскольку встроенная логика принтера обрежет все те строки, которые не смогут поместиться на странице.

Для того чтобы установить корректное имя используемого сетевого принтера можно воспользоваться средством Scriptomatic (scriptomatic.exe - его можно загрузить по адресу http://www.microsoft.com/technet/scriptcenter/tools/wmimatic.asp). В основном окне этой программы выберите класс Windows Management Instrumentation (WMI) Win32_Printer. Если вы предполагаете более полно автоматизировать ваш сценарий, то с помощью Scriptomatic вы также можете получить корректные свойства Win32_Printer для их дальнейшего использования.

А как быть в тех случаях, когда нужно просто организовать печать данных на принтер, установленный по умолчанию, не выясняя его точное имя? Для последних версий операционной системы, таких как Windows Server 2003 или Windows XP, которые содержат расширенные классы WMI, можно воспользоваться примером кода, приведенным на Листинге 3, где показано, как можно получить имя порта, к которому подключен принтер, используемый по умолчанию. При разработке данного примера я вновь использовал Scriptimatic для того чтобы выяснить, какими свойствами я могу манипулировать. На Листинге 3 меткой A обозначен фрагмент кода, который выполняет подключение к пространству имен rootcimv2 локального компьютера и возвращает набор установленных в системе принтеров и их атрибутов. Далее организуется просмотр элементов данного набора с помощью цикла For Each...Next. При этом выясняется, какой принтер используется по умолчанию, после чего в переменную strPrinterUNC записывается значение свойства PortName. По завершении цикла сценарий организует вывод файла на печать путем передачи его в порт принтера, используемого по умолчанию. Необходимо отметить, что пример, показанный на Листинге 3, не будет работать на системах с Windows 2000, поскольку в этой операционной системе недоступно свойство WMI objItem.PortName. Поэтому для Windows 2000 придется просмотреть список доступных принтеров, обратившись с помощью Scriptomatic к классу Win32_Printer, выбрать требуемый принтер и жестко прописать его имя в сценарии.

Альтернативный подход состоит в том, чтобы организовать запись в текстовый файл с помощью свойств Write и WriteLine объекта TextStream, а затем использовать код, аналогичный показанному в Листинге 3 для вывода файла на печать. Либо можно просто передавать каждую строку в порт соответствующего принтера и разрешать спулеру печатать файл после того как все его строки будут переданы в данный порт. В Листинге 4 (еще один вариант сценария для Windows 2003 и XP) показан пример кода, где с помощью простого цикла For...Next печатаются числа от 1 до 50. Здесь с помощью метода OpenTextFile объекта FileSystemObject организуется подключение объекта TextStream к принтеру, которое остается открытым до тех пор, пока оно не будет закрыто вызовом метода Close объекта TextStream, и документ не будет полностью напечатан.

Печать данных HTML

Как и многие другие разработчики сценариев, я часто формирую данные отчетов в виде текста в формате HTML. Разумеется, можно легко организовать процесс печати данных HTML с помощью объекта автоматизации Microsoft Internet Explorer (IE), однако следует учитывать, что IE 5.0 и более поздние его версии обычно выводят диалоговое окно печати, поскольку Microsoft считает, что процедура печати из IE затрагивает аспекты безопасности. Более подробно эта проблема обсуждается в статье Microsoft "Printing with the Internet Explorer WebBrowser Control", http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnie55/html/wb_print.asp.

Одним из путей решения данной проблемы является использование внешнего компонента для организации печати HTML-данных из сценариев. Таким компонентом является, например, ScriptX от MeadCo. Набор компонентов, реализующих функциональность печати ScriptX, доступен по адресу http://www.meadroid.com. В данной статье я не буду более подробно останавливаться на использовании ScriptX, вы можете сами загрузить данный компонент и попробовать с ним поработать.

Другой подход к программированию печати HTML-данных из сценариев состоит в использовании Microsoft Office. С Office можно работать двумя способами. Наименее очевидный метод - использовать мало популярную программу msohtmed.exe, которая обычно находится в каталоге C:program filesmicrosoft officeoffice11 (для Office 2003) либо в каталоге C:program filesmicrosoft officeoffice10 (для Office 2000). Данная программа используется аналогично Notepad. Например, для вывода на печать файла с именем MyLog.htm, можно применить показанную ниже команду:

"C:Program FilesMicrosoft
OfficeOffice11msohtmed.exe"
/p "C:MyLog.htm"

Наиболее распространенным решением является автоматизация с помощью Microsoft Word. Word хорошо работает в автоматическом режиме, и с его помощью можно открывать, читать и печатать текстовые документы. Пример реализации печати через Microsoft Word показан в Листинге 5. Здесь константе PRNT_BACKGROUND присваивается значение FALSE, что указывает на то, что процесс печати является должен выполняться в приоритетном (foreground) режиме, таким образом, сценарий не будет продолжать выполнение до тех пор, пока процесс печати не завершится. Константа DONT_SAVE также имеет значение FALSE. Это сделано для того, чтобы Word не перезаписывал документ HTML после его закрытия.

После задания пути к файлу HTML в переменной strFilePath сценарий создает новый экземпляр Word, а описатель приложения записывается в переменную appWord. Далее с помощью метода Open объекта Document открывается файл HTML, путь к которому содержится в переменной strFilePath, затем происходит печать этого документа с помощью метода PrintOut объекта Application. Метод PrintOut имеет дополнительные аргументы, с помощью которых можно указать дополнительные параметры печати, такие как фоновый (background) режим, режим двусторонней печати (duplex), количество печатаемых страниц и количество копий. Более подробно параметры метода PrintOut описаны в справочнике Microsoft Word Visual Basic Reference, который можно дополнительно установить вместе с программой Microsoft Word (см. раздел "Содержание", "Информация по программированию" справочной системы Microsoft Word). По завершении процесса печати метод Quit объекта Application закрывает Word без сохранения документа.

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

appWord.Visible = TRUE

Печать данных через Microsoft Excel

Когда сценарий в ходе выполнения формирует значительный объем выходных данных, часто бывает удобно распечатать их через Microsoft Excel для дальнейшего анализа. В Excel, как и в Word, печать данных осуществляется с помощью метода PrintOut. Однако здесь метод PrintOut может применяться к таким объектам как диаграммы (chart), диапазоны (range), листы (sheet), таблицы и книги.

В листинге 6 приведен образец простого сценария, предназначенного для заполнения книги Excel небольшим набором данных и последующего вывода этих данных на печать. После объявления переменных сценарий создает объект Excel Application и назначает ему переменную appExcel. Затем в данный объект добавляется книга, ее первому листу присваивается имя My Data, после чего данный лист выбирается в качестве рабочего.

Для заполнения первых девяти столбцов листа девятью строками данных в сценарии используются два цикла For…Next. Внутри второго цикла вызывается свойство Cell объекта Worksheet, которое обращается к каждой ячейке и вносит в нее формулу, для чего применяется свойство ячейки FormulaR1C1. В формуле используется функция Excel RAND(), с помощью которой для каждой из ячеек генерируется случайное число в диапазоне от 0 до 1.

И, наконец, сценарий делает приложение Excel видимым для пользователя и распечатывает выбранный лист из активного окна объекта Application. Здесь следует отметить, что я присвоил свойству Visible значение TRUE только для того чтобы показать вам, как работает сценарий. Если же Excel используется в рабочих сценариях, то его вовсе не обязательно делать видимым, а для закрытия Excel по завершении печати файла можно использовать следующий код:

appExcel.DisplayAlerts = False
appExcel.Quit

Если при вызове метода Quit объекта Application остались открытыми еще какие-либо таблицы с не сохраненными данными, Excel выводит соответствующее диалоговое окно, в котором вам будет предложено сохранить внесенные изменения. Один из способов избежать появления этого диалогового окна (например, если сценарий должен выполняться без вмешательства пользователя) состоит в том, чтобы перед вызовом метода Quit сохранить данные во всех открытых книгах. Другой подход состоит в том, чтобы присвоить свойству DisplayAlerts объекта Application значение False. В этом случае Excel просто закроется без вывода диалогового окна и, соответственно, без сохранения данных.

В отличие от Word, при работе с Excel сценарий не будет продолжать выполнение до тех пор, пока Excel не завершит процесс печати. У имеющегося в Excel метода PrintOut есть параметры, с помощью которых можно задавать номера начальной и конечной страниц диапазона печати, а также количество копий. Более подробно параметры метода PrintOut описаны в справочнике Microsoft Excel Visual Basic Reference, который можно дополнительно установить вместе с программой Microsoft Excel (см. раздел "Содержание", "Информация по программированию" справочной системы Microsoft Excel). Однако когда требуется распечатать только часть таблицы или в каких-то других случаях, когда требуется вручную выбрать параметры настройки страницы (PageSetup), необходимо использовать метод Excel PageSetup.

В Листинге 7 приведен фрагмент кода, иллюстрирующий то, как можно использовать возможности метода PageSetup. В начале с помощью трех констант определяется тип и ориентация бумаги, причем используются те имена и значения, которые используются внутри программы Excel. Свойство PrintArea определяет диапазон таблицы, предназначенный для печати - в данном случае будут распечатаны ячейки от B7 до D9. Для активации требуемого листа таблицы используется метод Activate объекта Worksheet. После того как требуемый лист активирован, получаем ссылку на него, используя свойство ActiveSheet объекта Application, затем с помощью метода PageSetup объекта ActiveSheet устанавливаем для данного листа параметры страницы. При первом вызове PageSetup для задания ориентации бумаги используется свойство Orientation, при втором вызове данного метода через свойство PageSize устанавливается размер бумаги. При третьем и четвертом вызове PageSetup используются свойства FitToPagesWide и FitToPagesTall, соответственно, которые указывают Excel, что необходимо сжать данные печати таким образом, чтобы весь объем выводимых данных разместился на указанном количестве страниц. Я убедился на личном опыте, что свойства FitToPagesWide и FitToPagesTall являются исключительно полезными и поэтому использую их часто.

Самый простой путь нахождения "правильных" параметров для методов и свойств этого интерфейса состоит в том, чтобы записать макрос, выполняющий ту задачу, которую вы хотите автоматизировать, а затем соответствующим образом отредактировать этот макрос. Чтобы найти значения констант, которые нужно определить в сценарии откройте редактор макросов и нажмите клавишу F2 или выберите из меню "View" пункт "Object Browser", после чего просмотрите содержимое класса Excel. Данный класс содержит перечень всех констант Excel. Если щелкнуть мышью по какой-либо константе, то в поле результатов появится ее описание, которое можно использовать для определения данной константы в сценарии.

Установка принтеров в Word и Excel

Последнее, что надлежит знать при организации печати из сценариев это то, как установить принтер. Когда выполняется печать файла Word или Excel из сценария требуемый принтер задается через свойство ActivePrinter объекта Application. Примеры задания различных принтеров и факсов показаны в Листинге 8.

Первая строка этого примера указывает на второй виртуальный сетевой порт на моем компьютере (Ne02) - это порт, к которому подключен принтер. Вторая строка обращается к порту принтера LPT1. Третья строка - пример использования имени UNC при подключении к принтеру. Четвертая строка указывает на виртуальный порт факса. Для того чтобы выяснить, какой порт соединен с принтером в настоящий момент, можно воспользоваться свойством ActivePrinter объекта Application.


ЛИСТИНГ 1. Пример организации печати через Notepad
Option Explicit
Dim strFilePath, wshShell
strFilePath = "C:MyLog.txt"
Set wshShell = WScript.CreateObject("WScript.Shell")
wshShell.Run "notepad.exe /p " & strFilePath

ЛИСТИНГ 2. Пример использования UNC-имен в описании пути к принтеру
Option Explicit
Const OVERWRITE = True
Dim strFilePath, strPrinterUNC, fso
strFilePath = "C:MyLog.txt"
strPrinterUNC = "SERVERPrinter Name"
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
fso.CopyFile strFilePath, strPrinterUNC, OVERWRITE

ЛИСТИНГ 3. Организация печати на принтер, установленный по умолчанию
Option Explicit
Const OVERWRITE = True
Dim strFilePath, objWMIService, colItems, objItem
Dim strPrinterUNC, fso
strFilePath = "C:MyLog.txt"
' BEGIN CALLOUT A
Set objWMIService = GetObject("winmgmts:.
ootcimv2")
Set colItems = _
	objWMIService.ExecQuery("Select * from Win32_Printer",,48)
For Each objItem in colItems
	If objItem.Default Then
		strPrinterUNC = objItem.PortName
		Exit For
	End If
Next
' END CALLOUT A
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
fso.CopyFile strFilePath, strPrinterUNC, OVERWRITE

ЛИСТИНГ 4. Пример организации построчной печати
Option Explicit
Const OVERWRITE = True
Const ForWriting = 2
Dim strFilePath, objWMIService, colItems, objItem
Dim strPrinterUNC, fso, tsPrinter, intCount
strFilePath = "C:MyLog.txt"
Set objWMIService = GetObject("winmgmts:.
ootcimv2")
Set colItems = _
	objWMIService.ExecQuery("Select * from Win32_Printer",,48)
For Each objItem in colItems
	If objItem.Default Then
		strPrinterUNC = objItem.PortName
		Exit For
	End If
Next
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set tsPrinter = fso.OpenTextFile(strPrinterUNC, ForWriting)
For intCount = 1 To 50
	tsPrinter.WriteLine intCount
Next
tsPrinter.Close

ЛИСТИНГ 5. Организация печати через Microsoft Word
Const PRNT_BACKGROUND = False
Const DONT_SAVE = False
Dim appWord, strFilePath
strFilePath =  "C:MyLog.htm"
Set appWord = WScript.CreateObject("Word.Application.8")
appWord.Documents.Open strFilePath
appWord.Application.PrintOut PRNT_BACKGROUND
appWord.Application.Quit DONT_SAVE
Set appWord = Nothing

ЛИСТИНГ 6. Организация печати через Microsoft Excel
Option Explicit
Dim appExcel, intRowIndex, intColIndex
Set appExcel = CreateObject("Excel.Application")
appExcel.Workbooks.Add
appExcel.Sheets("Sheet1").Name = "My Data"
appExcel.Sheets("My Data").Select
For intRowIndex = 1 to 9
	For intColIndex = 1 to 9
		appExcel.Cells(intRowIndex, intColIndex).FormulaR1C1 = _
			"=RAND()"
	Next
Next
appExcel.Visible=True
appExcel.ActiveWindow.SelectedSheets.PrintOut
Set appExcel = Nothing

ЛИСТИНГ 7. Использование метода PageSetup в Excel
Const xlLandscape = 2
Const xlPaperA4 = 9
Const xlPaperLetter = 1
appExcel.Worksheets("My Data").PageSetup.PrintArea = "$B$7:$D$9"
appExcel.Worksheets("My Data").Activate
appExcel.ActiveSheet.PageSetup.Orientation = xlLandscape
BEGIN COMMENT LINE
? In the following line, you can use any available constant
' that your printer supports (e.g., A4, Letter).
END COMMENT LINE
appExcel.ActiveSheet.PageSetup.PaperSize = xlPaperLetter
appExcel.ActiveSheet.PageSetup.FitToPagesWide = 1
appExcel.ActiveSheet.PageSetup.FitToPagesTall = 1

ЛИСТИНГ 8. Пример различных вариантов задания принтеров и факсов
appExcel.ActivePrinter = _
	"MyPrinter on NETWORKSERVER on Ne02:"
appExcel.ActivePrinter = "MyPrinter on LPT1:"
appWord.ActivePrinter = "HP LaserJet 4Mx on printerslaser4mx"
appWord.ActivePrinter = "Central Fax on Fax:"