Тема: Вызов функций Win 32 API и пример «асинхронного» программирования в TDMS
Аннотация
Для использования функций Win 32 API и функций других библиотек в скриптах для TDMS предлагается решение с помощью ActiveX компонента (СОМ-сервера) dynwrapx.dll. Данное решение позволило создать интерактивный html-виджет управляемый TDMS.TDMS и dynwrapx.dll. Win 32 API в действии
Библиотека dynwrapx.dll является результатом труда программиста Юрия Попова. Она написана на языке ассемблера GoAsm и распространяется бесплатно. Основное предназначение - вызов функций Win 32 API в WHS скриптах.
Перед началом использования данный компонент необходимо скопировать на жесткий диск и зарегистрировать в системе.
Зарегистрировать компонент можно двумя способами:regsvr32.exe <путь-к-компоненту>\dynwrapx.dll - для всех пользователей. regsvr32.exe /i <путь-к-компоненту>\dynwrapx.dll - для текущего пользователя (этот вид регистрации позволяет зарегистрировать компонент без наличия прав администратора).Скачать библиотеку dynwrapx.dll сфайлом справки можно по адресу http://www.script-coding.com/dynwrapx1_00.zip (версия 1.0.0.0 от 05.09.2008 г., архив 14 191 байт). В архиве находится сама библиотека и html-файл справки с подробным описанием библиотеки и примерами её использования.
Объект библиотеки создаётся следующим образом:Set Wrap = CreateObject("DynamicWrapper")Объявление функции производится так:
Wrap.Register "USER32.DLL", "FindWindowExA", "i=llsl", "f=s", "r=l"Параметры при объявлении содержат имя библиотеки, имя функции, а также:
i - описывает количество и тип данных параметров функции. Если функция не принимает параметры, этот параметр можно опустить. Параметр i является строкой, количество букв в которой равно количеству параметров объявляемой функции. Первая буква задаёт тип первого параметра, вторая - втрого и т.д.
f - тип вызова: _stdcall, _cdecl и т.д. Значение по умолчанию - _stdcall.
r - тип возвращаемых данных.
В примере используется тип данных Long, обозначается “l” (“эль”).
Передавать и принимать можно не только параметры, но и указатели на строки. В примере используется указатель “p” - в этом случае строка является просто буфером в памяти для хранения любых данных.
Компонент dynwrapx.dll содержит несколько дополнительных методов для работы с числами, строками и памятью. В примере будет использоваться:
Space( Count [, Char] ) – метод для создания строки (BSTR) заданной длины. Возвращает строковую переменную. Count - число символов (двухбайтных). Char - необязательный параметр: символ, которым будет заполнена строка. По умолчанию строка заполняется пробелами.
Пример использования библиотеки dynwrapx.dll для создания функции аналогичной DoEvents() в VB.
Создаваемая нами функция позволит в момент выполнения скрипта передать управление операционной системе, для обработки других событий. И после обработки системой всех событий из очереди возвращает управление обратно скрипту.
Данную функцию на языке VB можно описать с помощью стандартных функций Win 32 API:Private Type POINTAPI x As Long y As Long End Type Private Type MSG hwnd As Long message As Long wParam As Long lParam As Long time As Long pt As POINTAPI End Type Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" _ (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, _ ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long Private Declare Function TranslateMessage Lib "user32" _ (lpMsg As MSG) As Long Private Declare Function DispatchMessage Lib "user32" Alias "DispatchMessageA" _ (lpMsg As MSG) As Long Private Const PM_REMOVE = &H1 Private Sub DoEvents() Dim CurrMsg As MSG Do While PeekMessage(CurrMsg, 0, 0, 0, PM_REMOVE) <> 0 TranslateMessage CurrMsg DispatchMessage CurrMsg Loop End SubС помощью компонента dynwrapx.dll преобразуем данный код для использования функции в TDMS.
Для начала зарегистрируем компонент и объявим функции:Set Wrap = CreateObject("DynamicWrapperX") Wrap.Register "user32.dll", "PeekMessageA", "i=pllll", "r=l" Wrap.Register "user32.dll", "TranslateMessage", "i=p", "r=l" Wrap.Register "user32.dll", "DispatchMessage", "i=p", "r=l"Как вызывать функции с параметрами мы уже знаем, но в данном случае используется такой составной тип, как структура, например MSG. Заменим эту структуру на указатель «p». Он будет ссылаться на строку, содержащую 7 DWord (количество типов в MSG включая два типа в POINTAPI). Зарезервируем под эту строку 28 2-х байтных символа:
Msg = Wrap.Space(28)Окончательный код функции примет вид:
Function DoEvents() PM_REMOVE = &H1 Set Wrap = CreateObject("DynamicWrapperX") Wrap.Register "user32.dll", "PeekMessageA", "i=pllll", "r=l" Wrap.Register "user32.dll", "TranslateMessage", "i=p", "r=l" Wrap.Register "user32.dll", "DispatchMessage", "i=p", "r=l" Msg = Wrap.Space(28) Do While Wrap.PeekMessageA(Msg, 0, 0, 0, PM_REMOVE) <> 0 Wrap.TranslateMessage(Msg) Wrap.DispatchMessage(Msg) Loop End FunctionПример использования функции DoEvents для обработки нажатия кнопок на web-форме в TDMS.
Рассмотрим пример создания информационного виджета написанного на html+css+js и взаимодействующего с TDMS.
Для начала необходимо создать форму в TDMS и разместить на ней кнопку и объект ActiveX Microsoft Web Browser:$matches[1]Заранее созданную html-страницу назовём index.html и поместим на диск С.
Теперь, мы хотим, чтобы наша форма отображала необходимую html страничку при открытии TDMS. Для этого напишем обработку события Form_BeforeShow():Sub Form_BeforeShow(Form, Obj) Set WB = Form.Controls("ACTIVEX1").ActiveX WB.Navigate "C:\index.html" End SubДобавим эту форму в профиль, как панель главного окна. Перезагрузим TDMS и получим на главном окне наш «виджет». Кнопки html-страницы будут реагировать на указатель мыши, но они всё ещё не взаимодействуют с TDMS.
Иногда, панель на главном окне может не отображаться, даже если она помечена для отображения. В этом случае необходимо щелкнуть правой кнопкой мыши на стандартной панели TDMS, снять флажок напротив названия нашей формы и установить его обратно. После этих действий форма должна отобразиться.$matches[1]
Хотелось бы уточнить, что в коде html-страницы уже прописана обработка нажатия кнопок. При нажатии одной из кнопок происходит передача индекса кнопки в скрытое текстовое поле на странице. Таким образом, следующей нашей задачей будет постоянное наблюдение за текстовым полем html-страницы и при появлении индекса кнопки выполнять соответствующие команды в TDMS.Для реализации постоянного наблюдения за полем воспользуемся ранее написанной функцией “DoEvents()” в паре с функцией “WaitMessage()” библиотеки “user32.dll”. Поместим функцию “DoEvents()” в отдельную команду “CMD_DoEvents” для удобства вызова из разных скриптов. Теперь напишем обработку события нажатия кнопки формы “WEB”:
Sub BUTTON1_OnClick() Set Form = ThisForm 'получим доступ к окну браузера и html-документу Set WB = Form.Controls("ACTIVEX1").ActiveX Set doc = WB.document 'объявим функцию WaitMessage() Set DX = CreateObject("DynamicWrapperX") DX.Register "user32.dll", "WaitMessage", "r=l" 'Очищаем поле html-страницы a = doc.all("pole").setAttribute("value", "") 'Создаем постоянный цикл Do While Form.Controls("ACTIVEX1").Visible = True DX.WaitMessage DoEvents 'Цикл с условием на значение поля Do While doc.all("pole").getAttribute("value") = "" DX.WaitMessage' управление у системы DoEvents'и скрипт не мешает работе с TDMS Loop 'если появилось значение b = doc.all("pole").getAttribute("value") Select Case b Case 1 Set FiltMsgs = ThisApplication.Messages With FiltMsgs .Filter.TimeFrom = "12.02.2013" .Filter.On = True 'включить фильтр сообщений End With MsgBox "Всего " & FiltMsgs.Count & " писем." Case 2 MsgBox "На сегодня контактов нет." End Select 'очищаем поле html-страницы и продолжаем 'за ним наблюдать a = doc.all("pole").setAttribute("value", "") Loop End SubСохраним скрипт. Нажмем на панели инструментов TDMS “Вид-Обновить все” и получим полноценно рабочий виджет взаимодействующий с TDMS.
Готовый пример находится в архиве. Импортируйте в любую надстройку TDMS файл “html-виджет.tds”. Разместите файл “index.html” в корень диска С, зарегистрируйте библиотеку dynwrapx.dll. В TDMS добавьте форму в профиль, как панель главного окна. Перезагрузите TDMS.Выводы.
Библиотека dynwrapx.dll - небольшой ActiveX компонент, который может быть использован в TDMS. Библиотека позволяет вызывать произвольные функции из DLL-библиотек (например, win32 функции API) расширяя функциональные возможности системы.
С помощью данной библиотеки удалось портировать стандартную для VB функцию DoEvents на VBScript. Эта функция частично позволила применить в разработке надстроек TDMS принципы асинхронного программирования. В частности создать интерактивный html-виджет. Использование таких виджетов вносит разнообразие в строгий интерфейс системы TDMS, а также расширяет его функционал.Ссылки на статьи.
Для более подробной информации по библиотеке dynwrapx.dll рекомендую прочитать справку в архиве, а также следующие статьи:
Dynwrap.dll - http://www.script-coding.com/dynwrap.html
Вызов функций Win 32 API в 1C для 1С - http://infostart.ru/public/18636/
Эксперименты с функциями Win 32 API в 1C часть 2 для 1С - http://infostart.ru/public/18722/