Некоторые малоизвестные возможности элементов управления ActiveX
Создание обработчиков событий в HTML-документах
Система безопасности Microsoft Internet Exprorer и цифровая подпись
Динамическая инициализация элементов управления ActiveX в приложении
Технология COM (Component Object Model) активно развивалась корпорацией Microsoft в течение последних нескольких лет и продолжает развиваться и поддерживаться до сих пор. Поэтому сегодня существует множество публикаций, в которых объясняются принцип работы и назначение COM-объектов. Соответственно и технология ActiveX, как одно из направлений COM, также широко обсуждается в печати. Имеется достаточно литературы, где подробно рассказывается о принципе работы и назначении элементов управления ActiveX, об их создании, использовании, добавлении новых свойств и методов, о создании новых обработчиков событий и т.д. Вместе с тем некоторые аспекты создания и использования элементов управления ActiveX по-прежнему не вполне освещены в литературе. Настоящая публикация отчасти восполняет имеющиеся пробелы в доступных читателям описаниях создания и работы элементов управления ActiveX. В ней будет рассказано о создании обработчиков событий в HTML-документах, будут рассмотрены проблемы безопасности элементов управления ActiveX и динамического обращения к ним. В качестве средства разработки примеров используется Delphi 6. Предполагается, что читатель обладает опытом работы с этим средством разработки и, в частности, владеет основами применения COM и создания элементов управления ActiveX в Delphi.
Добавление новых свойств и обработчиков событий в элемент
управления ActiveX.
Тестирование ActiveX в HTML-документе
оздадим новый элемент управления ActiveX с помощью пункта меню Delphi File | New | Other…, выберем закладку ActiveX и вызовем эксперт ActiveX Library. Сохраним проект под именем AXTest. Затем вновь обратимся к пункту меню File | New | Other …| ActiveX и вызовем эксперт Active Form. В диалоге изменим свойство New ActiveX Name на AFTest. На полученную форму поместим метку (TLabel) и кнопку (TButton).
Создадим в этом элементе управления новое свойство, например текст метки, и назовем его LCaption. Для этого обратимся к пункту меню View | Type Library и в редакторе библиотеки типов отметим интерфейс IAFTest. Затем щелкнем по кнопке New property. В результате добавится новое свойство, имя которого следует изменить на LCaption. Поскольку заголовок является текстовой строкой, то сразу же за изменением имени в редакторе библиотеки типов необходимо из выпадающего списка Type выбрать значение BSTR (рис. 1).
После этого следует выполнить команду Refresh и в редакторе кода модуля AFTestImpl1.pas реализовать код для работы с этим свойством:
function TAFTest.Get_LCaption: WideString; begin Result:=Label1.Caption; end; procedure TAFTest.Set_LCaption(const Value: WideString); begin Label1.Caption:=Value; end;
В качестве нового события можно создать событие, связанное с нажатием кнопки Button1. Для добавления нового события в редакторе библиотеки типов отметим интерфейс IAFTestEvents и вызовем команду New Method. Метод назовем OnBtClick. Активируем закладку Parameters в редакторе библиотеки типов и в контроле Return Type вручную наберем слово void — оно не встречается в выпадающем списке (рис. 2).
В отличие от случая определения нового свойства элемента управления ActiveX, при создании нового события после выполнения команды Refresh в модуле AFTestImpl1.pas не появится никаких заготовок для реализации кода. И это понятно: код для обработки события будет реализован в клиентском приложении, которое будет использовать данный элемент управления ActiveX. В самом же элементе управления ActiveX необходимо вызвать этот обработчик. Поскольку было решено, что созданное событие связано с нажатием кнопки Button1, то вызываем его из метода Button1.OnClick:
procedure TAFTest.Button1Click(Sender: TObject); begin if FEvents <> nil then FEvents.OnBtClick; end;
Проверка if FEvents <> nil обязательна, так как клиентское приложение может не поддерживать нотификационный интерфейс, и в этом случае попытка вызова несуществующего метода приведет к исключению.
На этом создание тестового элемента управления ActiveX можно считать законченным. Для тестирования его работы в HTML-документе необходимо обратиться к пункту меню Delphi 6 Project | WEB deployment options. Но перед вызовом этой команды нужно убедиться, что на компьютере установлен Internet Information Server (IIS) или Personal WEB server (PWS). Если один из них установлен, то необходимо выбрать директорию, содержимое которой можно передавать в Internet, причем с правом доступа на чтение. По умолчанию имя такого каталога C:\InetPub\WWWRoot, но это имя может быть изменено при администрировании IIS или PWS. В последнем случае надо просмотреть список виртуальных директорий на IIS (PWS) и выбрать (или создать) подходящую.
Итак, выполним команду меню Project | WEB deployment options и заполним диалог (рис. 3).
Обратите внимание на то, что параметры Target Dir и Target URL должны ссылаться на одну и ту же директорию, но в случае Target Dir это путь относительно локального компьютера, а в случае Target URL — относительно «гостя», обращающегося к этой же директории через Internet. В Target URL указывается IP-адрес (или имя) компьютера, а также имя виртуальной директории (если это не Home-директория). Полезно также включить опцию Use CAB file compression — это позволит примерно в два раза уменьшить сетевой трафик при передаче элемента управления ActiveX на клиентский компьютер.
После заполнения всех опций следует выполнить команду меню Delphi — Project/WEB deploy. Затем нужно запустить Microsoft Internet Explorer и понизить в нем уровень безопасности. Для этого в Microsoft Internet Explorer вызывается команда Tools/Internet Options, выбирается закладка Security и уровень безопасности понижается до Low (причина, почему это необходимо сделать, будет объяснена ниже). Далее, из Microsoft Internet Explorer обращаемся к созданной Web-странице, на которой имеется ссылка на элемент управления ActiveX; в данном случае ее URL — http://192.168.0.2/AXTest.htm. Первая часть этого URL совпадает с параметром Target URL заполненной диалоговой панели WEB Deployment Options, а вторая часть является именем проекта с расширением *.htm. После получения одного или нескольких диалоговых панелей с сообщениями о потенциально опасном содержимом элемента управления ActiveX, в которых необходимо подтвердить, что это опасное содержимое нужно запустить, можно увидеть работу этого элемента управления в Microsoft Internet Explorer (рис. 4).
Если эту картинку получить не удалось, то дальнейшие действия бесполезны. Причины, по которым не удается запустить элемент управления ActiveX в Microsoft Internet Explorer, могут быть следующими:
- не установлен IIS или PWS;
- неправильно заполнены опции в диалоговой панели WEB Deployment Options;
- система безопасности не понижена до Low-уровня.
Создание обработчиков событий в HTML-документах
HTML-документах можно не только помещать параметры для элементов управления ActiveX, но и создавать обработчики событий на языках VBScript и JavaScript. Сразу же оговоримся, что в спецификацию Sun JavaScript обработчики событий для элементов управления ActiveX не входят — это разработка Microsoft. Но поскольку использование ActiveX на Web-страницах также является разработкой Microsoft, то проблема с обработчиками событий решается очень просто: в браузере, где клиент может работать с элементами управления ActiveX, будут работать и обработчики событий.
Для создания обработчика событий в HTML-документе воспользуемся предыдущим проектом. В созданный файл AXTest.htm внесем следующие изменения (добавленный код выделен жирным шрифтом):
<HTML> <HEAD> <SCRIPT LANGUAGE="VBScript"> <!-- Sub TestControl_OnBtClick TestControl.LCaption="Run" End Sub --> </SCRIPT> </HEAD> <H1> Delphi 6 ActiveX Test Page </H1><p> You should see your Delphi 6 forms or controls embedded in the form below. <HR><center><P> <OBJECT classid="clsid:BDBD2538-7050-4662-9531-88B3E548F79C" codebase="http://192.168.0.2/AXTest.cab#version=1,0,0,0" id=TestControl width=216 height=173 align=center hspace=0 vspace=0 > </OBJECT> </HTML>
Для работы со скриптовыми языками элемент управления должен обладать идентификатором (id= в тэге <OBJECT>), по имени которого к нему осуществляется доступ из кода на этих языках. Имя обработчика события должно начинаться с идентификатора, далее следует нижнее подчеркивание (_), а затем — имя обработчика события, как оно определено в диспинтерфейсе элемента управления ActiveX. Если обработчик события имеет параметры, то они тоже приводятся.
Обратившись к этой странице из Microsoft Internet Explorer и нажав кнопку Run script, можно увидеть изменения заголовка метки (рис. 5).
Если элемент управления ActiveX содавать с помощью Delphi 3, то при попытке выполнения скрипта при некоторых настройках Microsoft Internet Explorer может появиться сообщение браузера о потенциально опасном содержимом программы. Как этого избежать, рассказывается в следующем разделе.
Система безопасности Microsoft Internet Exprorer и цифровая подпись
ифровая подпись помещается в элементы управления ActiveX, которые планируется распространять с помощью Internet. Для того чтобы получить соответствующий электронный сертификат, необходимо обратиться к авторизованным компаниям, выдающим такие сертификаты. В этом случае вы должны быть готовы представить очень подробную информацию о себе (если сертификат частный) или о своей компании. Одна из таких авторизованных компаний — VeriSign; ее электронный адрес: http://www.verisign.com/. После предоставления информации о деятельности компании (или частного лица) VeriSign может выслать соответствующие файлы, если придет к заключению, что ваша деятельность в программировании безопасна. Эти файлы далее используются для создания электронной подписи под элементом управления ActiveX. В России в настоящее время нет авторизованных компаний, которые могли бы выдать электронный сертификат международного образца.
Электронная подпись, помимо сведений о фирме-производителе, несет и ряд другой полезной информации. Так, например, если файл *.OCX был изменен после добавления электронной подписи, то об этом будет немедленно сообщено перед запуском такого элемента управления.
Для коммерческой разработки элементов управления ActiveX желательно приобрести Microsoft ActiveX SDK. Кроме детальной документации и ряда полезных ресурсов он содержит программу MAKECER, которая генерирует тестовые сертификаты.
Таким образом, получение международного электронного сертификата в нашей стране представляет сегодня серьезную проблему. В то же время отсутствие у пользователя электронной подписи приводит либо к постоянным напоминаниям ему об этом (или даже к запрету на загрузку элементов управления ActiveX при высоком уровне безопасности браузера), либо заставляет его отключить систему безопасности Internet. Конечно, наличие электронного сертификата не гарантирует отсутствие потенциально опасного содержимого, но, по крайней мере, позволяет клиенту установить источник опасного содержимого. Кроме того, он перекодирует файл с использованием современных шифровальных алгоритмов и подсчитывает контрольные суммы. Если кто-нибудь попытается внести изменения в код элемента управления ActiveX, такая попытка будет немедленно обнаружена при помощи контрольных сумм и этот элемент управления ActiveX не будет работать в Microsoft Internet Explorer. Поэтому наличие электронной подписи желательно даже при работе в интрасетях, а уж при работе элемента управления ActiveX в Internet она просто необходима.
Второй уровень защиты реализуется для элементов управления ActiveX, которые могут читать данные из HTML-документа и для обработки событий которых используется код на скриптовых языках, содержащийся в HTML-документах. HTML-документ можно легко редактировать. Как новые параметры в HTML-документе, так и выполняемые скрипты для элемента управления ActiveX могут оказаться бессмысленными. Более того, можно легко создать элемент управления ActiveX, в котором, например, при чтении буквы «A» в качестве значения какого-либо свойства выполняется форматирование жесткого диска, в результате чего он становится опасным при инициализации параметров. Такая особенность поведения элемента управления ActiveX известна разработчику, и в этом случае он обязан проинформировать Microsoft Internet Explorer о недопустимости инициализации данных и/или выполнения скриптов. О том, что элемент управления ActiveX безопасен, тоже необходимо сообщить Microsoft Internet Explorer, о чем и пойдет речь в данном разделе.
Вернемся к предыдущему проекту. Все тесты, описанные здесь, выполнены с Microsoft Personal Web Server 5.0. и Microsoft Internet Explorer 5.0. Уровень безопасности Microsoft Internet Explorer следует установить равным Сustom. Значения всех опций, относящихся к элементам управления ActiveX в появляющемся при этом диалоге, установим равными Prompt.
Если наш элемент управления AXTest зарегистрирован в системном реестре, записи о нем нужно ликвидировать с помощью выбора пункта меню Delphi Run | Unregister ActiveX server. После этого следует заполнить диалог Web Deployment Options. Далее c помощью любого текстового редактора откроем HTML-страницу, полученную в результате выполнения команды Project | Web deploy, и поместим туда строку:
<PARAM NAME="LCaption" VALUE="Text at label">,
а также скрипт c обработчиком события OnBtClick, как это описано в предыдущем разделе. Затем можно начать тестировать систему безопасности Microsoft Internet Explorer.
После первого обращения к HTML-странице, содержащей ActiveX, происходит его загрузка и он копируется в каталог WINNT\Downloaded Program Files. Далее проверяется наличие электронной подписи (которая в нашем случае отсутствует). Если уровень защиты, установленный в Microsoft Internet Explorer, соответствует Low, пользователь получит сообщение о том, что может быть запущено на выполнение потенциально опасное содержимое. Если пользователь не возражает против этого, то происходит регистрация полученного файла *.OCX в системном реестре и при помощи интерфейса IPersistPropertyBag считываются его свойства с HTML-страницы (см. выше). При этом возобновляется диалог, из которого становится ясно, что хотя наш элемент управления и безопасен, но к нему могут обращаться из скриптов (рис. 6).
Кроме того, следует обратить внимание на опцию «Initialize and script ActiveX controls not marked as safe» в диалоговой панели Security Settings браузера Microsoft Internet Explorer. Хотя значение опции было установлено равным Prompt и из HTML-документа производится инициализация параметра URL, предупреждение не было получено. Таким образом, Microsoft Internet Explorer считает данный элемент управления ActiveX безопасным с точки зрения инициализации данных и выполнения скриптов.
Причина этого заключается в том, что элементы управления ActiveX, cозданные с помощью версий Delphi старше 3-й, поддерживают интерфейс IObjectSafety. В этом интерфейсе определяются два метода:
function GetInterfaceSafetyOptions(const riid: TGUID; out pdwSupportedOptions: DWORD; out pdwEnabledOptions: DWORD) : HResult; function SetInterfaceSafetyOptions(const riid : TGUID; const dwOptionSetMask: DWORD; const dwEnabledOptions: DWORD) : HResult;
В качестве первого параметра (riid) используется ссылка либо на интерфейс IDispatch, что позволит использовать ActiveX как сервер автоматизации для клиента без его аутентификации, либо IPersistPropertyBag, что разрешает инициализацию данных, либо IActiveScript, что разрешает работу скриптов ActiveX. Соответственно в методе GetInterfaceSafetyOptions в переменных pdwSupportedOptions и pdwEnabledOptions последние версии Delphi автоматически устанавливают комбинации флагов, определенные в модуле ActiveX.pas:
INTERFACESAFE_FOR_UNTRUSTED_CALLER (= 1, разрешает анонимный доступ к интерфейсу)
INTERFACESAFE_FOR_UNTRUSTED_DATA (= 2, разрешает анонимному пользователю посылать данные в интерфейс).
Предположим, что создатель элемента управления ActiveX считает, что при выполнении скриптов или при некорректной инициализации данных этот элемент управления может нанести клиенту ущерб. В таком случае он обязан переписать реализованные методы IObjectSafety. Если элемент управления ActiveX реализован в классе TActiveXControl, то это не составляет труда, поскольку оба метода IObjectSafety объявлены виртуальными в секции protected. Но для класса-потомка TActiveForm это сделать невозможно, так как активная форма не является потомком класса TActiveXControl. Для того чтобы изменить методы IObjectSafety в активной форме, необходимо вновь реализовать указанный интерфейс. При этом методы нового интерфейса «затеняют» старые и, следовательно, именно они будут вызываться клиентами.
Сначала следует добавить интерфейс IObjectSafety в список поддерживаемых интерфейсов TAFTest:
TAFTest = class(TActiveForm, IFilledBox, IObjectSafety)
Далее в секции private определим два метода — GetInterfaceSafetyOptions и SetInterfaceSafetyOptions c директивой вызова stdcall, а в секции implementation создадим реализацию этих методов:
function TAFTest.GetInterfaceSafetyOptions(const IID: TIID; pdwSupportedOptions, pdwEnabledOptions: PDWORD): HResult; var Unk: IUnknown; begin if (pdwSupportedOptions = nil) or (pdwEnabledOptions = nil) then begin Result := E_POINTER; Exit; end; pdwSupportedOptions^ := 0; pdwEnabledOptions^ := 0; result:=S_OK; end; function TAFTest.SetInterfaceSafetyOptions(const IID: TIID; dwOptionSetMask, dwEnabledOptions: DWORD): HResult; begin Result := E_NOTIMPL; end;
Результат тестирования этого приложения отличается от предыдущего (рис. 7).
Мы видим, что Internet Explorer предупреждает пользователя о возможной опасности содержимого. При значении уровня безопасности Middle этот элемент управления будет запущен автоматически, но инициализация его данных не будет выполнена, так же как не будут выполняться и скрипты. Тот же эффект достигается и при нажатии кнопки No в диалоге, который предоставляет Microsoft Internet Explorer (см. рис. 7).
Динамическая инициализация элементов управления ActiveX в приложении
орошо известно, что компоненты VCL можно создавать динамически, во время выполнения приложения. Например, если в обработчике события, связанного с нажатием на кнопку, выполнить код:
procedure TForm1.Button1Click(Sender: TObject); begin with TEdit.Create(self) do begin Parent:=Self; Left:=10; Top:=10; end; end;
то при нажатии кнопки во время выполнения появится однострочный редактор текста. Если бы компонент TEdit не находился на палитре компонентов, то данный код также был бы успешно выполнен — при динамическом создании VCL-классов не требуется, чтобы они были на палитре компонентов.
В Delphi с элементами управления ActiveX и работают следующим образом: сначала вызывается команда меню Component | Import ActiveX control, выбранный ActiveX помещается на палитру компонентов, затем он помещается на форму, а в инспекторе объектов изменяются свойства и создаются обработчики событий. Возникает вопрос: а как можно инициализировать элемент управления ActiveX во время выполнения приложения – то есть, не регистрируя ActiveX на палитре компонентов, во время выполнения приложения создать его рабочий экземпляр?
Из сказанного ранее ясно, что, помимо инициализации и создания рабочего экземпляра элемента управления ActiveX, для работы приложения требуется создать VCL-контейнер, куда он будет помещаться. Роль такого контейнера в Delphi выполняет класс TOleControl, который объявлен в модуле OleCtrls.pas. Базовый метод этого класса — InitControlData. В указанном методе необходимо определить GUID фабрики классов элемента управления ActiveX, число обработчиков событий и ссылку реализованного на клиенте интерфейса обработчиков событий, а также ссылку на лицензионный интерфейс, необходимый для вызовов методов IClassFactory2. Метод InitControlData вызывается автоматически после отработки конструктора TOleControl.
Создадим новое приложение и в секции Interface объявим новый класс-потомок TOleControl:
type TRTActiveX = class(TOleControl) protected FControlData: TControlData; procedure InitControlData; override; public constructor EmbeggAX(AOwner: TComponent; AParent: TWinControl; AClassID: TGUID; Rect:TRect); end;
Методы InitControlData и EbeggAX реализуем следующим образом:
constructor TRTActiveX.EmbeggAX(AOwner: TComponent; AParent: TWinControl; AClassID: TGUID; Rect:TRect); begin with FControlData do begin ClassID:=AClassID; EventCount:=0; EventDispIDs:=nil; LicenseKey:=nil; Flags:=$00000000; end; inherited Create(AOwner); Self.parent:=AParent; Self.visible:=true; Self.Left:=Rect.Left; Self.Top:=Rect.Top; Self.Width:=Rect.Right-Rect.Left; Self.Height:=Rect.Bottom-Rect.Top; end; procedure TRTActiveX.InitControlData; begin ControlData:=@FControlData; end;
В конструкторе заполняем структуру TControlData и создаем контейнер в заданной области. В методе InitControlData свойству ControlData присваиваем адрес заполненной в конструкторе структуры. Обратите внимание на то, что структура TControlData заполняется до вызова конструктора класса-предка. Так делать не рекомендуется; необходимость подобной конструкции в данном примере обусловлена тем, что метод InitControlData, в котором используется структура FControlData, вызывается из конструктора класса-предка.
Поместим на форму кнопку и создадим простой обработчик события:
procedure TForm1.Button1Click(Sender: TObject); begin TRTActiveX.EmbeggAX(Self,Self,StringToGUID('{22D6F312-B0F6-11D0-94AB-0080C74C7E95}'),Rect(10,10,300,300)); end;
Теперь можно запустить созданное приложение и во время выполнения нажать кнопку. Элемент управления ActiveX появится в указанной области. Изменив GUID фабрики классов на {0002E510-0000-0000-C000-000000000046}, можно увидеть другой результат (рис. 8).
Как первый, так и второй из тестируемых здесь элементов управления не были зарегистрированы в палитре компонентов Delphi. В принципе, таким же образом можно обратиться к любому из зарегистрированных в системном реестре COM-серверов, имеющих ключ реестра Control в секции с GUID фабрики классов. Наличие этой секции гарантирует поддержку COM-сервером интерфейсов IOleClientSite, IOleControlSite, IOleInplaceSite, необходимых для отображения элемента управления ActiveX на клиенте.
КомпьютерПресс 2'2002