Краткое введение
COM означает "Component Object Model" (Объектная модель компонентов). Это способ от Microsoft для связи программного обеспечения, используя единый интерфейс. Эти интерфейсы определены в COM-объекты.
До появления COM нужно было знать точное выполнение программы, прежде чем вы могли бы "взаимодействовать" с ней. Используя COM, теперь вы можете "общаться" с его определенным объектом. Единственное, что вы должны знать это имена объектов, которые используются и какие "Свойства" и "Методы" у них есть.
Это две основные характеристики объекта. Вы можете видеть "свойство" как хранение данных объекта. "Метод" можно рассматривать как внутренний вызов функции, чтобы сделать что-то с данными.
Это зависит от многого. AutoIt имеет множество встроенных функций, а также огромную библиотеку Стандартных функций пользователя. Вы можете сделать большую часть программирования с этим. Однако, если вам нужны особые "интерфейсы" для других приложений, то используя COM можете сэкономить несколько строк скрипта. скриптёры должны знать, что наличие COM-объектов во многом зависит от операционной системы и установленного программного обеспечения. В приведённых ниже примерах всё испытано под 'простой' Windows XP Professional версией с Microsoft Office 2000.
Скажем, Вы хотите свернуть все открытые окна. Вы можете сделать это, используя обычные функции AutoIt такие как WinList и WinSetState. Однако, 2 строчки из COM-кода могут дать Вам тот же результат:
$oShell = ObjCreate("shell.application")
$oShell.MinimizeAll
Примечание: Данный пример не самый короткий путь, чтобы минимизировать все окна после введения WinMinimizeAll() в AutoIt.
В первой строке мы создаём новый объект под названием "shell.application". Это внутренний объект Windows, определённый в shell32.dll. Указатель на новый объект присваивается переменной $oShell. $oShell отныне переменная объекта.
Во 2-й строчке мы используем метод "MinimizeAll" к объекту oShell. Это свернёт все окна.
Все версии ОС Windows имеют огромное количество внутренних объектов различного назначения. И такие приложения как Excel или Word тоже имеют свой набор объектов.
Тем не менее, порой трудно получить список всех существующих объектов, определенных в вашей системе с соответствующими свойствами и методами. Поиск по Microsoft.com или Google.com может дать вам некоторые подсказки об объекте, который Вы хотите использовать.
Например, Вы можете найти информацию об объекте "shell.application" по ссылке:
http://msdn.microsoft.com/en-us/library/bb774094.aspx
Чтобы получить обзор на все объекты, установленные в вашей системе, "OLE/COM Object Viewer" является очень полезным инструментом. Об этой программе будет рассказано в отдельном разделе ниже.
Возьмём другой пример. Мы хотим получить исходный код из определенных веб-страниц. Вы можете использовать внутреннюю функцию InetGet(), чтобы сохранить результат в файл и получить его обратно через FileRead(). Но эти строчки кода выполняют то же самое:
$oHTTP = ObjCreate("winhttp.winhttprequest.5.1")
$oHTTP.Open("GET", "http://www.AutoItScript.com")
$oHTTP.Send()
$HTMLSource = $oHTTP.Responsetext
Переменная (строковая) $HTMLSource теперь содержит полный HTML-код страницы AutoItScript.com (то есть, верхний HTML-Frame).
(Информация о "winhttp.winhttprequest" можно найти по ссылке:
http://msdn.microsoft.com/en-us/library/aa384106.aspx )
Пожалуйста, учтите: Существование объектов зависит от операционной системы компьютера и установленных программ. Например, winhttp.winhttprequest.5.1 объект есть только на ПК с установленным Internet Explorer версии 5 или выше. Когда вы публикуете скрипты, которые используют COM-объекты, убедитесь что объекты существуют на всех компьютерах.
Object переменные ведут себя несколько иначе, чем другие виды AutoIt переменных. Объект не является реальным значением, а "указатель" к чему-то вне скрипта. Таким образом, Вы не можете выполнить арифметические или сравнительные действия с Object переменными. При присвоении Object переменной другого значения, "указатель" автоматически будет очищен. Вы можете, например, принудительно удалить объект, присвоив ему любое число или текстовое значение.
$oHTTP = ObjCreate("winhttp.winhttprequest.5.1") ; Создаёт объект
$oHTTP = 0 ; Удаляет объект
Вам не нужно удалять объекты после завершения. Если скрипт заканчивается, AutoIt пытается завершить все активные ссылки на объекты, что были созданы в скрипте. То же самое происходит, когда вы определили локальные переменные объекта внутри функции, а функция заканчивается возвращением.
Очень популярным применением COM является "автоматизация" программ. Вместо того чтобы использовать регулярные AutoIt функции, такие как Send() или WinActivate(), вы можете использовать объекты, которые определены в программе.
Это пример 'автоматизации' Microsoft Excel:
$oExcel = ObjCreate("Excel.Application") ; Создаёт Excel объект
$oExcel.Visible = 1 ; Отобразить объект Excel
$oExcel.WorkBooks.Add ; Добавляет новую книгу
$oExcel.ActiveWorkBook.ActiveSheet.Cells(1, 1).Value = "Text" ; Заполняет ячейку
Sleep(4000) ; Посмотреть результаты в течении 4-х секунд
$oExcel.ActiveWorkBook.Saved = 1 ; Имитация сохранения книги
$oExcel.Quit ; Выход из Excel
Сложность управления другими программами зависит от конкретной программы, а не от AutoIt скрипта. Если что-то не работает, как ожидалось вам придётся обратиться к документации приложений, а не к справке AutoIt.
В AutoIt'е два особых выражения разработаны для применения в COM:
With/EndWith и For/In/Next циклы.
Выражение With/EndWith не добавляет функциональности, но делает Ваш скрипт легко читаемым. Например, предыдущий пример использования Excel мог быть также написан вот так:
$oExcel = ObjCreate("Excel.Application") ; Создаёт Excel объект
With $oExcel
.Visible = 1 ; Отобразить объект Excel
.WorkBooks.Add ; Добавляет новую книгу
.ActiveWorkBook.ActiveSheet.Cells(1, 1).Value = "Text" ; Заполняет ячейку
Sleep(4000) ; Посмотреть результаты в течении 4-х секунд
.ActiveWorkBook.Saved = 1 ; Имитация сохранения книги
.Quit ; Выход из Excel
EndWith
Этот пример не сэкономит вам много текста, но, когда ваш объект использует длинный ряд свойств/методов, вы можете сильно сократить его с помощью WITH.
Цикл For...In требуется, когда используется коллекции. Коллекции представляют собой особый тип объектов, которые состоят из нескольких суб-объектов. Вы могли видеть их как массивы (на самом деле, For..In выражение также работает на Array-переменных).
Ниже указан пример For..In цикла. Этот пример использует обычныйl AutoIt массив, так что не имеет ничего общего с COM. Это просто, чтобы показать Вам принцип:
Local $sString = "" ; Строка для присоединения текста
Local $aArray[4]
$aArray[0] = "A" ; Заполняем массив
$aArray[1] = 0 ; с несколькими
$aArray[2] = 1.3434 ; различными
$aArray[3] = "Example Text" ; примерами значений.
For $iElement In $aArray ; Начало цикла...
$sString = $sString & $iElement & @CRLF
Next
; Теперь показываем результаты
MsgBox(0, "Пример For..In по массиву", "Результат: " &
@CRLF & $sString)
В большинстве случаев вы не можете использовать «нормальные» методы объекта для извлечения элементов из коллекции. В "COM'-справках сказано, что вы должны" перечислить" их. И здесь приходит на помощь цикл FOR..IN.
В примере Excel, указанном ниже, цикл проходит по ячейкам A1:O16 в текущем активном листе. Если одна из ячеек имеет значение меньше 5, возвращается значение 0 (ноль):
$oExcel = ObjCreate("Excel.Application") ; Создаёт Excel объект
$oExcel.Visible = 1 ; Отобразить объект Excel
$oExcel.WorkBooks.Add ; Добавляет новую книгу
Local $aArray[16][16] ; Это строки
For $i = 0 To 15 ; просто
For $j = 0 To 15 ; пример
$aArray[$i][$j] = $i ; создания некоторых
Next ; заполненных ячеек.
Next
$oExcel.activesheet.range("A1:O16").value = $aArray ; Заполнение ячеек числами примера
Sleep(2000) ; Ожидаем 2 сек. перед продолжением
For $iCell In $oExcel.ActiveSheet.Range("A1:O16")
If $iCell.Value < 5 Then
$iCell.Value = 0
EndIf
Next
$oExcel.ActiveWorkBook.Saved = 1 ; Имитация сохранения книги
Sleep(2000) ; Ожидаем 2 сек. перед закрытием
$oExcel.Quit ; Выход из Excel
Следующие особенности AutoItCOM требуют глубокого знания COM событий и обработку ошибок COM.
Если вы новичок в программировании COM, пожалуйста, прочитайте хорошую документацию COM в первую очередь.
Библией COM является книга под названием "Inside OLE 2" Kraig Brockschmidt (Microsoft Press).
Вы также можете найти некоторые COM-ресурсы в Интернете (не связанных с AutoIt):
http://msdn.microsoft.com/en-us/library/ms694363.aspx (введение)
http://www.garybeene.com/vb/tut-obj.htm (об объектах в Visual Basic)
http://java.sun.com/docs/books/tutorial/java/concepts/ (Использование объектов в Java)
http://msdn.microsoft.com/archive/en-us/dnarguion/html/drgui082399.asp (События объектов в C++)
http://www.garybeene.com/vb/tut-err.htm (Обработка ошибок в Visual Basic)
Обычная Автоматизация COM в основном использует одностороннюю связь. Вы "спрашиваете" Объект о любых свойствах или результатах метода. Однако COM-объект может "ответить" Вашему скрипту, когда он устраивает его.
Это может быть очень удобно в тех случаях, когда вам нужно подождать несколько связанных COM-действий.
Вместо написания своего рода цикла, запрашивая объект, произошло ли что-то интересное, вы можете позволить объекту самому вызывать конкретные UDF в вашем скрипте. Тем временем вы можете делать другие вещи в вашем скрипте (почти) одновременно.
Не все объекты поддерживают события. Вы должны тщательно прочитать документацию объекта, чтобы узнать - поддерживает он события или нет.
Если да, то второе - надо знать тип событий, что он поддерживает. COM AutoIt может только получать события типа "отправки".
Наконец, вы должны знать имена событий объекта, которые он может генерировать, в том числе их аргументы (если таковые имеются).
Только тогда, когда у вас есть вся эта информация, вы можете начинать построение AutoIt скрипт с использованием COM событий.
Ниже приводится отрывок из скрипта, который демонстрирует, как получать события из Internet Explorer:
$oIE = ObjCreate("InternetExplorer.Application.1") ; Create an
Internet Explorer Object
$EventObject = ObjEvent($oIE, "IEEvent_", "DWebBrowserEvents") ; Старт получения событий.
$oIE.url = "http://www.autoitscript.com" ; Загрузка примера веб-страницы
; Теперь $oIE объект генерирует события во время загрузки веб-страницы.
; Они обрабатываются в случае функции как показано ниже.
; Здесь вы можете позволить скрипту ждать, пока пользователь не захочет закончить.
...(Ваш код здесь)...
$EventObject.stop ; Скажем IE, что мы хотим остановить принятие событий
$EventObject = 0 ; Убиваем событие объекта
$oIE.quit ; Выход из IE
$oIE = 0 ; Убираем IE из памяти (не так уж необходимо)
Exit ; Конец основного скрипта
; Несколько функций событий Internet Explorer.
;
; Для полного списка Функций событий IE, см. MSDN WebBrowser documentation по ссылке:
; http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.aspx
Func IEEvent_StatusTextChange($Text)
; В окончательном скрипте (см. ссылку ниже) мы покажем содержимое в GUI Edit box.
GUICtrlSetData($GUIEdit, "IE Status text changed to: " &
$Text & @CRLF, "append")
EndFunc ;==>IEEvent_StatusTextChange
Func IEEvent_BeforeNavigate($URL, $Flags, $TargetFrameName, $PostData, $Headers, $Cancel)
; В окончательном скрипте (см. ссылку ниже) мы покажем содержимое в GUI Edit box.
; Примечание: декларация отличается от той, что на MSDN.
GUICtrlSetData($GUIEdit, "BeforeNavigate: " & $URL & " Flags: " & $Flags & @CRLF, "append")
EndFunc ;==>IEEvent_BeforeNavigate
Нажмите здесь , чтобы посмотреть итоговый скрипт.
Главная строка в этом скрипте: $EventObject=ObjEvent($oIE,"IEEvent_",...).
Эта функция получает объект $oIE и перенаправляет его события к AutoIt функциям, имена которых начинаются с MYEvent_. Третий параметр опционален. Он используется, когда объект имеет несколько интерфейсов событий, и вы не хотите, чтобы AutoIt выбирал один автоматически.
Объект, ответственный за непрерывное изменение маршрута это $EventObject. Эта переменная не требует дальнейшего внимания, если не требуется остановить события.
Для остановки перенаправления события, вы не можете просто удалить переменную $EventObject="". Причина в том, что "вызов" объекта всё еще содержит ссылки на эту переменную, и он не потеряет её, пока сам объект не завершит работу. Вы можете решить эту проблему путем убийства "вызова" объекта, но вы также можете сказать объекту, что вы не хотите получать любые события с помощью: $EventObject.Stop. Тогда вы можете (но не обязательно) убить событие, присвоив ему какое-либо значение, например: $EventObject=""
Если Вы знаете имена событий $oIE , то можете осуществить События в которых вы заинтересованы при создании AutoIt UDF с именем IE Event_Eventname(необязательные аргументы). Убедитесь, что вы используете правильное количество аргументов и в правильном порядке, как указано для данного события функции. В противном случае возможно закончите с неожиданными значениями.
Вы не должны выполнять все функции событий. Те, что не реализованы просто игнорируются.
Больше примеров скриптов с использованием функций событий COM можно найти в каталоге tests в AutoIt 3.1.1.xx beta ZIP файле-дистрибутиве, который можно загрузить по ссылке: http://www.autoitscript.com/autoit3/files/beta/autoit/COM/
Ограничения на COM события в AutoIt
Некоторые объекты (напр., 'WebBrowser') передают аргументы их функциям событий 'по ссылке'. Это сделано для того, чтобы позволить пользователю изменить эти аргументы и передать его обратно на объект. Тем не менее, AutoIt использует свою собственную схему переменной, которая не совместима с COM переменным. Это означает, что все значения из объектов должны быть преобразованы в AutoIt переменные, тем самым теряя ссылку на исходный объём памяти. Возможно в ближайшем будущем мы сможем решить это ограничение для вас!
Использование COM без надлежащей обработки ошибок может быть очень сложным. Особенно, если вы не знакомы с объектами в вашем скрипте.
Скрипт AutoIt немедленно остановит выполнение при обнаружении ошибки COM. Это значение по умолчанию, а также безопасные настройки. В этом случае вы должны принять меры в скрипте, чтобы предотвратить появление ошибки.
Только если нет никакого способа, чтобы предотвратить ошибки COM, вы можете установить "Error Handler", в котором вы будете действовать после возникновения ошибки. Это не решение, чтобы глючный скрипт заработал правильно. Он также не поймает, не-COM ошибки, связанные со скриптом (например, декларации и синтаксические ошибки).
Обработка ошибок осуществляется таким же образом, как обычное событие COM, используя ObjEvent() и определенные пользователем функции COM-событий. Единственная разница заключается в использовании фиксированной строки "AutoIt.Error" в качестве имени объекта.
Пример:
Global $iEventError = 0 ; будет выбрано в случае возникновения ошибок. Необходимо восстановить после обработки.
$oMyError = ObjEvent("AutoIt.Error", "ErrFunc") ; Установка обработчика ошибок
; Выполняется преднамеренный отказ здесь (объект не существует)
$oIE = ObjCreate("InternetExplorer.Application")
$oIE.visible = 1
$oIE.bogus
If $iEventError Then
MsgBox(0, "", "There was an error on the
previous line.")
$iEventError = 0 ; Reset after displaying a COM Error occurred
EndIf
Exit
; Это мой собственный обработчик ошибок
Func ErrFunc()
$HexNumber = Hex($oMyError.number, 8)
MsgBox(0, "", "We intercepted a COM Error !"
& @CRLF & _
"Number is: " & $HexNumber & @CRLF & _
"WinDescription is: " & $oMyError.windescription)
$iEventError = 1 ; Use to check when a COM Error occurs
EndFunc ;==>ErrFunc
Одна особенность обработчика событий ошибки, это возвращаемое значение. Это AutoIt объект ошибок, который содержит некоторые полезные свойства и методы. Его реализация частично основана на "Err" Object в VB(script):
Свойства AutoIt Error Object:
.number | Значение Windows HRESULT из COM-вызова |
.windescription | FormatWinError() текст, заимствованный из .number |
.source | Название объекта генерации ошибки (содержимое из ExcepInfo.source) |
.description | Описание ошибки исходного объекта (содержимое из ExcepInfo.description) |
.helpfile | Файл справки об ошибке исходного объекта (содержимое из ExcepInfo.helpfile) |
.helpcontext | Source Object's helpfile context id number (contents from ExcepInfo.helpcontext) |
.lastdllerror | Число, возвращаемое из GetLastError() |
.scriptline | Строка скрипта, в которой произошла ошибка |
Методы AutoIt Error Object:
.raise | Вызывает событие ошибки, инициированное пользователем |
.clear | Очищает содержимое Error Object (то есть цифры в 0, строки в "") |
Примечание для тех, кто пишет UDF
У Вас может быть только ОДНА ошибка обработчика событий в активном AutoIt скрипте. Если Вы пишете UDF, содержащие COM функции, Вы можете проверить, имеет ли пользователь обработчик ошибок, установленный как указано ниже:
$sFuncName = ObjEvent("AutoIt.Error")
If $sFuncName <> "" Then
MsgBox(0, "Test", "User has installed Error Handler
function: " & $sFuncName)
EndIf
Если обработчик ошибки не был активным, вы можете временно установить свой собственный во время вызова UDF.
Тем не менее, вы не сможете остановить существующий обработчик ошибок, без освобождения переменной, которой он был назначен. Если автор скрипта установил обработчик ошибок COM, то это уже его ответственность за использование собственной функции, которая будет также иметь возможность перехватывать COM ошибки, вызванные UDF.
"OLE/COM Object Viewer" это очень удобный инструмент, чтобы получить быстрый обзор на все COM-объекты, установленные в вашей системе. It is part of the Windows 2000 resource kit and can be downloaded for free from: http://www.microsoft.com/downloads/details.aspx?familyid=5233b70d-d9b2-4cb5-aeb6-45664be858b6&displaylang=en
Установка этой программы немного неудобная. При установке не будет создаваться иконка в меню Пуск для вас. Вместо этого файл с именем oleview.exe будет установлен в каталог C:\Program Files\Resource Kit (по умолчанию).
При запуске файла oleview.exe, некоторые системы будут жаловаться об отсутствующем файле iviewers.dll. Этот файл требуется, но как ни странно, не включен в последнюю установку. Вы можете получить этот dll из старой версии oleview.exe по ссылке: http://download.microsoft.com/download/2/f/1/2f15a59b-6cd7-467b-8ff2-f162c3932235/ovi386.exe. Будут установлены файлы по умолчанию в каталог C:\MSTOOLS\BIN. Вам нужен только файл iviewer.dll. Скопируйте его в ту же директорию, где находится OLEView.exe, а затем зарегистрируйте DLL с помощью командной строки: regsvr32 iviewers.dll.
Давайте выполним пример с Oleviewer. Запустите его и следуйте далее: Object Classes->Grouped by Component Category->Control->Microsoft Web Browser.
В левой колонке Вы видите все COM интерфейсы, что были определены для этого объекта. Мы поговорим о них позже. Присмотритесь к правой колонке. Она содержит много информации о том, как использовать этот объект в AutoIt скрипт. Наиболее важным является "VersionIndependentProgID". Это имя, используемое в функциях ObjCreate, ObjGet или ObjEvent. Кроме того, он содержит каталог и имя файла, содержащего объект. Это может быть файл EXE, DLL или OCX. InProcServer32 означает, что объект работает в том же потоке, сценарий (в процессе). Когда Вы видите LocalServer32, объект работает как отдельный процесс. Объект также должен содержать библиотеку типов (строчки, после "TypeLib="), иначе он не может быть использован в скрипте AutoIt.
Интерфейсы в левой колонке используются для нескольких способов взаимодействия с объектом. Некоторые из них используются для хранения (IStorage, IPersist), другие для вложения в GUI (IOleObject, IOleControl). AutoIt использует IDispatch интерфейс для автоматизации. Этот интерфейс "разоблачает" все методы и свойства сценариев, которые поддерживает объект. Если его нет, то вы не сможете использовать объект в AutoIt скрипт.
Давайте взглянем на этот интерфейс. Щелкните правой кнопкой мыши на имени IDispatch и выберите "View..." из контекстного меню. Затем нажмите кнопку "View TypeInfo...". (Примечание: если эта кнопка неактивна, Вы не зарегистрировали файл iviewers.dll, или объект не имеет библиотеку типов)
Окно "ITypeInfo Viewer" показывает только информацию, которая поставляется вместе с объектом. Если разработчик решил не включать в файл справки, вы увидите только названия методов/свойств и больше ничего. Библиотека типов "Microsoft Web Browser", однако, достаточно обширна. Просто щёлкните элемент в левой колонке и описание будет показано на рисунке справа. Иногда вам придется просматривать "наследуемые интерфейсы", чтобы получить больше методов для объекта.
Синтаксис описанных методов/свойств в стиле C/C++. Свойство, описанное как "HRESULT Resizable([in] VARIANT_BOOL pbOffline)", может быть переписано в AutoIt как: $Resizable=$Object.Resizable ($Object содержит объект, созданный с ObjCreate или ObjGet).
Эти термины часто путают с COM, но они имеют разное значение:
OOP = Object Oriented Programming (Объектно-Ориентированное Программирование) Технология программирования, в которой программные компоненты, собранные из многократно используемых блоков, известны как объекты.
DDE = Dynamic Data Exchange (Динамический обмен данными).
Можно сказать, что это предшественник COM. Раньше применялось IPC для передачи информации и команд между различными приложениями.
OLE =Object Linking and Embedding (Связывание и внедрение объекта)
В своей первой версии, OLE была расширенной версией DDE на "использование" данных из одной программы в другую. Нынешнее поколение OLE построено на началах COM и является частью ActiveX.
Автоматизация = Это способ манипулирования объектами другого приложения. Используется в OLE, ActiveX и COM.
ActiveX = Следующее поколение OLE с автоматизацией, поначалу в основном разработанное для взаимодействия между приложениями по сети (в частности, веб-браузеры). ActiveX построено на основе COM.
DCOM=Distributed COM (распределённый COM). Небольшое изменение в COM, даёт возможность общаться между различными физическими компьютерами.
.NET (dot Net)= В действительности это не часть программного обеспечения, а "идея" от Microsoft для объединения почти "всего" посредством (их) программного обеспечения. "dot Net" используется в основном для веб-служб.
COMmunist = Это не сторонник COM, а тот, кто верит в коммунизм (теория о том, что простые люди должны владеть всем имуществом).