Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Связка ActiveX - Internet Explorer


Спрашиваю я детей, как то:
- А что самое главное при работе с компьютером?
А они мне отвечают:
- Главное сразу не упасть в обморок.

А знаете ли вы, что на Delphi можно писать ActiveX компоненты? Конечно знаете. А что с их помощью можно взаимодействовать с Internet Explorer? Это может быть интересно для профессиональных вебмастеров, скажете вы, но я не согласен. "Простой" программист тоже может найти массу применений этому. Здесь будет описано одно из них. Все мы лазим (ходим и т.д.) по интернету. И вы тоже - раз читаете эти строки :). А не случалось ли вам, случайно где-то побывав, что-то прочитав и благополучно забыв адрес сайта через некоторое время вдруг понять, что там было именно то, что вам сейчас срочно понадобилось? Можно конечно посмотреть History браузера, можно залезть в кэш "руками" и попытаться найти там что-то. А можно написать компонент, который бы искал слова в файлах кэша (в общем случае в любых HTML-файлах) и выводил бы на просмотр требуемые файлы. Связать этот компонент с Эксплорером - и вперед. Что удобно - вся работа происходит в эксплорере: и поиск, и,естественно, просмотр. При этом для Delphi-программиста не нужны особые знания языка HTML, скриптовых языков и т.п. Достаточно знать несколько основных конструкций (а уж справочных руководств в интернете навалом - хотя бы на http://www.citforum.ru). Написанный ActiveX-компонент вставляется в HTML-страничку. Вот пример простейшей странички


<HTML>
   <HEAD>
     <TITLE>Поиск</TITLE>
   </HEAD>
   <BODY>
     <P ALIGN=CENTER>
       <OBJECT ID="findword1" - {при помощи этого тэга компонент вставляется в страничку}
       CLASSID="CLSID:47E50425-E611-11D3-970A-4854E82B17E6"
       CODEBASE="C:\PATH\FINDWORDS.OCX">
       </OBJECT>
     </P>
   </BODY>
</HTML>



В этом примере ActiveX-компонент, находящийся в файле C:\PATH\FINDWORDS.OCX вставляется в HTML-страничку. Но важно отметить, что эта страничка откроется только в Microsoft Internet Explorer версии 4 и старше. Пишут, что третий эксплорер тоже поддерживает тэг <OBJECT>, но сам не пробовал, не знаю. Браузеры Netscape, Opera и какие еще там бывают, его не поддерживают.

Итак, тэг <OBJECT> вставляет в страничку ActiveX-компонент. Его атрибут CLASSID указывает идентификатор класса нашего компонента. При создании в Delphi компонента с нуля ему автоматически присваивается этот идентификатор класса. ID="findword1" - имя объекта. Здесь можно писать любое имя. По нему мы в дальнейшем будем ссылаться на наш компонент в теле странички из скриптов-процедур обработки событий. Далее, для того, чтобы наш компонент мог использоваться прикладными программами, он должен быть зарегистрирован в реестре. Зарегистрировать его можно программой regsvr32, которая по умолчанию находится в каталоге [System]. Например так: [regsvr32 C:\PATH\FINDWORDS.OCX]. Если при открытии странички Explorer не находит в реестре указанный компонент, то он ищет его в местоположении, указанном атрибутом CODEBASE. Здесь может быть полный путь к файлу, если он находится на вашем жестком диске или даже URL-адрес (со всеми сопутствующими атрибутами, как то http:// и т.д.).Т.е, если эксплорер встретил ссылку на компонент, а этого компонента нет на вашей машине, он может загрузить его из интернета с указанного адреса. Кстати, атрибут CLASSID - обязательный, именно по нему производится "идентификация" класса. А атрибут CODEBASE - необязательный. В случае, когда он опущен, если компонент уже зарегистрирован в системе, то он отобразится в вашей страничке, если не зарегистрирован - страничка будет пустой. И наконец если эксплорер сам регистрирует компонент, он переписывает файл OCX в папку [Windows\Downloaded program files].

Для того, чтобы вручную не писать скрипты подсоединения ActiveX компонентов, я советую скачать программу Microsoft ActiveX Control Pad. Эта программа предназначена для внедрения ActiveX-компонентов в HTML-странички. После ее работы определение компонента выглядит примерно так:


<OBJECT ID="findword1"
CLASSID="CLSID:47E50425-E611-11D3-970A-4854E82B17E6"
CODEBASE="C:\PATH\FINDWORDS.OCX">
<PARAM NAME="Visible" VALUE="-1">
<PARAM NAME="AutoScroll" VALUE="0">
<PARAM NAME="AutoSize" VALUE="0">
<PARAM NAME="AxBorderStyle" VALUE="1">
<PARAM NAME="Caption" VALUE="findword">
<PARAM NAME="Color" VALUE="2147483663">
<PARAM NAME="Font" VALUE="MS Sans Serif">
<PARAM NAME="KeyPreview" VALUE="0">
<PARAM NAME="PixelsPerInch" VALUE="96">
<PARAM NAME="PrintScale" VALUE="1">
<PARAM NAME="Scaled" VALUE="-1">
<PARAM NAME="DropTarget" VALUE="0">
<PARAM NAME="HelpFile" VALUE="">
<PARAM NAME="DoubleBuffered" VALUE="0">
<PARAM NAME="Enabled" VALUE="-1">
<PARAM NAME="BiDiMode" VALUE="0">
<PARAM NAME="Cursor" VALUE="0">
<PARAM NAME="filename" VALUE="nothing">
</OBJECT>



Т.е. эта программа сама подставляет полное определение компонента (его CLASSID, например). Правда, полученный код иногда приходится подправлять вручную. Например может потребоваться убрать явное указание высоты и ширины объекта.

Теперь подходим к самому главному: как сделать сам компонент (чтобы было что вставлять в нашу страничку :). Итак, в Delphi делаем New\ActiveX\Active form. В окошке Active Form Wizard выбираем Threading model=Apartment. Другие threading models не работают с IE 4. Выглядит это так: компонент в страничке открывается, но иногда вдруг выскакивает Access violation. (обычно на событие Create). Модель же Both работает с IE 5. Флажок "Include Design-Time licence" лучше не устанавливать. Дальше открывается новая форма, где вы можете размещать свои кнопки-текстбоксы, определять реакцию на события и т.д.

Далее будут описаны некоторые хитрости. Например, нужно хранить некоторые данные во внешнем файле. Я столкнулся со следующим: мой компонент на разных машинах размещал свои файлы в разных местах: на одной в каталоге Windows, на другой - на рабочем столе. Был найден такой выход: пусть страничка по требованию компонента возвращает ему каталог, в котором она находится. Для этого на форму я поместил PageControl, сделал закладки невидимыми и на OnShow (у формы ActiveX компонента нет события OnShow) одной из страниц поставил генерацию собственного события OnWantDir. А в теле HTML-странички соответственно реакцию на него:


<SCRIPT LANGUAGE="VBScript">
<!--
Sub findword1_OnWantDir()
findword1.page_location = location.href
end sub
-->

</SCRIPT>



Далее, это событие OnShow происходит сразу после создания экземпляра компонента. Так вот, если событие OnWantDir генерировать непосредственно в нем (в OnShow), то видимо что-то в недрах Windows не успевает провернуться и машина виснет. Поэтому пришлось повесить на форму таймер, на OnShow таймер запускать, и уже на OnTimer как раз и вызывать свое событие OnWantDir. Интервал у таймера я поставил в полсекунды. Конечно можно было бы хранить свои файлы например в каталоге [Windows], но почему-то функция GetWindowsDirectory при вызове из ActiveX-компонента возвращала ошибку, хотя тут же нормально отрабатывала из обыкновенного приложения (exe). То же и с GetSystemDirectory и GetTempDirectory. Кто не знает как делать собственные свойства и события - кликайте сюда.

Как сделать компонент тиражируемым? Чтобы пользователь смог работать с ним сразу же, не запуская никаких дополнительных программ, не указывая всяких-разных путей и т.д. Вот пример HTML-странички:


<html>
 <HEAD>
  <title>Поиск</title>
  <SCRIPT LANGUAGE="VBScript">
  <!--
   Sub Procedure1()
   location.href = findword1.NewStroke
   {Получить от компонента имя файла
и открыть его для просмотра. Эта
процедура запускается при
возникновении события OnDocClick. Location - объект
Explorer'а (см. документацию по VBScript)}
   end sub
  -->

  </SCRIPT>
 </HEAD>
 <BODY>
  <SCRIPT LANGUAGE="VBScript">
  <!--
   Sub findword1_OnWantDir()
   findword1.page_location = location.href
   {Получить текущий каталог, т.е.
свойству page_location объекта присвоить
местоположение нашей странички}

   end sub
   Sub findword1_OnDocClick()
   {При возникновении события OnDocClick
вызвать процедуру Procedure1 (открыть файл
для просмотра)}
   call Procedure1()
   end sub
  -->

  </SCRIPT>
  <p align = "center">
   <OBJECT ID="findword1"
   CLASSID="CLSID:47E50425-E611-11D3-970A-4854E82B17E6"
   CODEBASE="findwords.ocx">
   {Здесь просто имя файла без
пути. Explorer зарегистрирует компонент
невидимо для пользователя, взяв
его из текущего каталога (страничка
и файл OCX находятся в одном каталоге)}
   <PARAM NAME="Visible" VALUE="-1">
   <PARAM NAME="AutoScroll" VALUE="0">
   <PARAM NAME="AutoSize" VALUE="0">
   <PARAM NAME="AxBorderStyle" VALUE="1">
   <PARAM NAME="Caption" VALUE="findword">
   <PARAM NAME="Color" VALUE="2147483663">
   <PARAM NAME="Font" VALUE="MS Sans Serif">
   <PARAM NAME="KeyPreview" VALUE="0">
   <PARAM NAME="PixelsPerInch" VALUE="96">
   <PARAM NAME="PrintScale" VALUE="1">
   <PARAM NAME="Scaled" VALUE="-1">
   <PARAM NAME="DropTarget" VALUE="0">
   <PARAM NAME="DoubleBuffered" VALUE="0">
   <PARAM NAME="Enabled" VALUE="-1">
   <PARAM NAME="BiDiMode" VALUE="0">
   <PARAM NAME="Cursor" VALUE="0">
   <PARAM NAME="filename" VALUE="nothing">
   <PARAM NAME="page_location" VALUE="">
  </OBJECT>
  </p>
 </BODY>
</html>



И еще раз:

  1. Открываем нашу страничку (в IE 4 и выше)
  2. Если компонент зарегистрирован, он сразу показывается, если не зарегистрирован, то регистрируется и показывается. При этом:
  3. После создания выдерживается пауза в полсекунды и запрашивается текущий каталог (и страничка и сам OCX-файл находятся в одном каталоге, который и будет текущим).
  4. Если нужно открыть на просмотр какую либо страничку (выбранную пользователем в процессе работы из списка), то свойству компонента (при внедрении его в страничку правильнее будет называть его уже объектом) присваивается значение (имя файла), генерируется событие. Процедура-скрипт обработчик этого события читает свойство и отрывает требуемый файл.

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay