Blog. Just Blog

Обработка событий IWebBrowser на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Обработка событий IWebBrowser на Ассемблере
Обработка событий IWebBrowser на Ассемблере

В предыдущей статье про работу со встроенным браузером я написал, что статус полной загрузки страницы можно отслеживать при помощи таймера и вызова метода get_ReadyState интерфейса IWebBrowser2. Способ имеет место быть, но также имеет немало недостатков. Правильное решение этой задачи - получения сигналов от объекта браузера и обработка событий IWebBrowser. Пришлось провести пару бессонных ночей в отладчике, но результат меня порадовал.

Как и при любой другой работе с COM-объектами, процесс начинается с описания нужных структур, констант и GUID'ов. Какие-то вам уже знакомы по предыдущим публикациям, какие-то новые.
  1. ; GUID {00000000-0000-0000-C000-000000000046}
  2. IID_IUnknown \
  3.     dd 000000000h
  4.     dw 00000h
  5.     dw 00000h
  6.     db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
  7.  
  8. ; GUID {D30C1661-CDAF-11D0-8A3E-00C04FC9E26E}
  9. IID_IWebBrowser2 \
  10.     dd 0D30C1661h
  11.     dw 0CDAFh
  12.     dw 011D0h
  13.     db 08Ah, 03Eh, 000h, 0C0h, 04Fh, 0C9h, 0E2h, 06Eh
  14.  
  15. ; GUID {8856F961-340A-11D0-A96B-00C04FD705A2}
  16. CLSID_WebBrowser \
  17.     dd 08856F961h
  18.     dw 0340Ah
  19.     dw 011D0h
  20.     db 0A9h, 06Bh, 000h, 0C0h, 04Fh, 0D7h, 005h, 0A2h
  21.  
  22. ; GUID {B196B284-BAB4-101A-B69C-00AA00341D07}
  23. IID_IConnectionPointContainer \
  24.     dd 0B196B284h
  25.     dw 0BAB4h
  26.     dw 0101Ah
  27.     db 0B6h, 09Ch, 000h, 0AAh, 000h, 034h, 01Dh, 007h
  28.  
  29. ; GUID {B196B286-BAB4-101A-B69C-00AA00341D07}
  30. IID_IConnectionPoint \
  31.     dd 0B196B286h
  32.     dw 0BAB4h
  33.     dw 0101Ah
  34.     db 0B6h, 09Ch, 000h, 0AAh, 000h, 034h, 01Dh, 007h
  35.  
  36. ; GUID {34A715A0-6587-11D0-924A-0020AFC7AC4D}
  37. IID_DWebBrowserEvents2 \
  38.     dd 034A715A0h
  39.     dw 06587h
  40.     dw 011D0h
  41.     db 092h, 04Ah, 000h, 020h, 0AFh, 0C7h, 0ACh, 04Dh
  42.  
  43. ; IID_IWebBrowser2 Interface
  44. struct IWebBrowser2
  45.     ; IUnknown
  46.     QueryInterface           dd ?   ; 000h
  47.     AddRef                   dd ?   ; 004h
  48.     Release                  dd ?   ; 008h
  49.     ; IWebBrowser2
  50.     GetTypeInfoCount         dd ?   ; 00Ch
  51.     GetTypeInfo              dd ?   ; 010h
  52.     GetIDsOfNames            dd ?   ; 014h
  53.     _Invoke                  dd ?   ; 018h
  54.     GoBack                   dd ?   ; 01Ch
  55.     GoForward                dd ?   ; 020h
  56.     GoHome                   dd ?   ; 024h
  57.     GoSearch                 dd ?   ; 028h
  58.     Navigate                 dd ?   ; 02Ch
  59.     Refresh                  dd ?   ; 030h
  60.     Refresh2                 dd ?   ; 034h
  61.     Stop                     dd ?   ; 038h
  62.     get_Application          dd ?   ; 03Ch
  63.     get_Parent               dd ?   ; 040h
  64.     get_Container            dd ?   ; 044h
  65.     get_Document             dd ?   ; 048h
  66.     get_TopLevelContainer    dd ?   ; 04Ch
  67.     get_Type                 dd ?   ; 050h
  68.     get_Left                 dd ?   ; 054h
  69.     put_Left                 dd ?   ; 058h
  70.     get_Top                  dd ?   ; 05Ch
  71.     put_Top                  dd ?   ; 060h
  72.     get_Width                dd ?   ; 064h
  73.     put_Width                dd ?   ; 068h
  74.     get_Height               dd ?   ; 06Ch
  75.     put_Height               dd ?   ; 070h
  76.     get_LocationName         dd ?   ; 074h
  77.     get_LocationURL          dd ?   ; 078h
  78.     get_Busy                 dd ?   ; 07Ch
  79.     Quit                     dd ?   ; 080h
  80.     ClientToWindow           dd ?   ; 084h
  81.     PutProperty              dd ?   ; 088h
  82.     GetProperty              dd ?   ; 08Ch
  83.     get_Name                 dd ?   ; 090h
  84.     get_HWND                 dd ?   ; 094h
  85.     get_FullName             dd ?   ; 098h
  86.     get_Path                 dd ?   ; 09Ch
  87.     get_Visible              dd ?   ; 0A0h
  88.     put_Visible              dd ?   ; 0A4h
  89.     get_StatusBar            dd ?   ; 0A8h
  90.     put_StatusBar            dd ?   ; 0ACh
  91.     get_StatusText           dd ?   ; 0B0h
  92.     put_StatusText           dd ?   ; 0B4h
  93.     get_ToolBar              dd ?   ; 0B8h
  94.     put_ToolBar              dd ?   ; 0BCh
  95.     get_MenuBar              dd ?   ; 0C0h
  96.     put_MenuBar              dd ?   ; 0C4h
  97.     get_FullScreen           dd ?   ; 0C8h
  98.     put_FullScreen           dd ?   ; 0CCh
  99.     Navigate2                dd ?   ; 0D0h
  100.     QueryStatusWB            dd ?   ; 0D4h
  101.     ExecWB                   dd ?   ; 0D8h
  102.     ShowBrowserBar           dd ?   ; 0DCh
  103.     get_ReadyState           dd ?   ; 0E0h
  104.     get_Offline              dd ?   ; 0E4h
  105.     put_Offline              dd ?   ; 0E8h
  106.     get_Silent               dd ?   ; 0ECh
  107.     put_Silent               dd ?   ; 0F0h
  108.     get_RegisterAsBrowser    dd ?   ; 0F4h
  109.     put_RegisterAsBrowser    dd ?   ; 0F8h
  110.     get_RegisterAsDropTarget dd ?   ; 0FCh
  111.     put_RegisterAsDropTarget dd ?   ; 100h
  112.     get_TheaterMode          dd ?   ; 104h
  113.     put_TheaterMode          dd ?   ; 108h
  114.     get_AddressBar           dd ?   ; 10Ch
  115.     put_AddressBar           dd ?   ; 110h
  116.     get_Resizable            dd ?   ; 114h
  117.     put_Resizable            dd ?   ; 118h
  118. ends
  119.  
  120. ; IID_IConnectionPointContainer Interface
  121. struct IConnectionPointContainer
  122.     ; IUnknown
  123.     QueryInterface       dd ?   ; 000h
  124.     AddRef               dd ?   ; 004h
  125.     Release              dd ?   ; 008h
  126.     ; IConnectionPointContainer
  127.     EnumConnectionPoints dd ?   ; 00Ch
  128.     FindConnectionPoint  dd ?   ; 010h
  129. ends
  130.  
  131. ; IID_IConnectionPoint Interface
  132. struct IConnectionPoint
  133.     ; IUnknown
  134.     QueryInterface              dd ?   ; 000h
  135.     AddRef                      dd ?   ; 004h
  136.     Release                     dd ?   ; 008h
  137.     ; IConnectionPoint
  138.     GetConnectionInterface      dd ?   ; 00Ch
  139.     GetConnectionPointContainer dd ?   ; 010h
  140.     Advise                      dd ?   ; 014h
  141.     Unadvise                    dd ?   ; 018h
  142.     EnumConnections             dd ?   ; 01Ch
  143. ends
  144.  
  145. ; DWebBrowserEvents2 Interface
  146. struct DWebBrowserEvents2
  147.     ; IUnknown
  148.     QueryInterface   dd ?   ; 000h
  149.     AddRef           dd ?   ; 004h
  150.     Release          dd ?   ; 008h
  151.     ; DWebBrowserEvents2
  152.     GetTypeInfoCount dd ?   ; 00Ch
  153.     GetTypeInfo      dd ?   ; 010h
  154.     GetIDsOfNames    dd ?   ; 014h
  155.     _Invoke          dd ?   ; 018h
  156.     refcount         dd ?
  157. ends
  158.  
  159. CLSCTX_INPROC_SERVER  = 0x01
  160. CLSCTX_INPROC_HANDLER = 0x02
  161. CLSCTX_LOCAL_SERVER   = 0x04
  162. CLSCTX_REMOTE_SERVER  = 0x10
  163.  
  164. CLSCTX_SERVER = CLSCTX_INPROC_SERVER + CLSCTX_LOCAL_SERVER\
  165.                 + CLSCTX_REMOTE_SERVER
  166. CLSCTX_ALL    = CLSCTX_INPROC_HANDLER + CLSCTX_SERVER
  167. S_OK          = 0
  168.  
  169. VARIANT_TRUE = -1
  170. VARIANT_FALSE = 0
  171.  
  172. VT_BSTR = 8
  173.  
  174. DISPID_DOCUMENTCOMPLETE = 259
Теперь немного теории. Когда объект IWebBrowser2 создан и подключен к диалоговому окну, у этого объекта можно запросить интерфейс так называемой точки соединения. Для этого сперва получаем интерфейс IConnectionPointContainer суб-объекта источника, от которого исходят вызовы к интерфейсу объекта. Для получения событий через метод FindConnectionPoint, указав в качестве идентификатор исходящего интерфейса DWebBrowserEvents2. В дальнейшем приложение будет использовать эту точку соединения, чтобы получить доступ к уведомлениям объекта браузера. Но для этого надо выполнить еще два действия. Во-первых, нам придется самостоятельно реализовать все без исключения методы интерфейса IWebBrowserEvents и заполнить соответствующую структуру.
  1. ;----------------------------------------------------------------------------
  2. ; Обработчик метода QueryInterface
  3. ;----------------------------------------------------------------------------
  4. proc IWebBrowserEvents_QueryInterface pthis:DWORD, iid:DWORD, ppvObject:DWORD
  5.         pusha
  6.  
  7.         mov     eax,[ppvObject]
  8.         cmp     eax,0
  9.         jne     @f
  10.         ; E_POINTER
  11.         mov     eax,0x80004003
  12.         jmp     .loc_ret
  13. @@:
  14.         ; Это интерфейс DWebBrowserEvents2?
  15.         push    4
  16.         pop     ecx
  17.         mov     esi,[iid]
  18.         mov     edi,IID_DWebBrowserEvents2
  19.         xor     eax,eax
  20.         repe    cmpsd
  21.         jz      .loc_call
  22.  
  23.         ; Это интерфейс IUnknown?
  24.         push    4
  25.         pop     ecx
  26.         mov     esi,[iid]
  27.         mov     edi,IID_IUnknown
  28.         xor     eax,eax
  29.         repe    cmpsd
  30.         jz      .loc_call
  31.  
  32.         ; E_NOINTERFACE
  33.         mov     eax,0x80004002
  34.         jmp     .loc_ret
  35. .loc_call:
  36.         mov     eax,[pthis]
  37.         ; Установить интерфейс
  38.         mov     ecx,[ppvObject]
  39.         mov     [ecx],eax
  40.         mov     ecx,[eax]
  41.         stdcall dword [ecx+DWebBrowserEvents2.AddRef],eax
  42. .loc_ok:
  43.         ; S_OK
  44.         xor     eax,eax
  45. .loc_ret:
  46.         mov     [esp+28],eax
  47.         popa
  48.         ret
  49. endp
  50.  
  51. ;----------------------------------------------------------------------------
  52. ; Обработчик метода AddRef
  53. ;----------------------------------------------------------------------------
  54. proc IWebBrowserEvents_AddRef pthis:DWORD
  55.         mov     eax,[pthis]
  56.         inc     [eax+DWebBrowserEvents2.refcount]
  57.         mov     eax,[eax+DWebBrowserEvents2.refcount]
  58.         ret
  59. endp
  60.  
  61. ;----------------------------------------------------------------------------
  62. ; Обработчик метода Release
  63. ;----------------------------------------------------------------------------
  64. proc IWebBrowserEvents_Release pthis:DWORD
  65.         push    ecx
  66.         mov     eax,[pthis]
  67.         mov     ecx,[eax+DWebBrowserEvents2.refcount]
  68.         or      ecx,ecx
  69.         jz      @f
  70.         dec     [eax+DWebBrowserEvents2.refcount]
  71.         dec     ecx
  72. @@:
  73.         mov     eax,ecx
  74.         pop     ecx
  75.         ret
  76. endp
  77.  
  78. ;----------------------------------------------------------------------------
  79. ; Заглушка для метода GetTypeInfoCount
  80. ;----------------------------------------------------------------------------
  81. proc IWebBrowserEvents_GetTypeInfoCount pthis:DWORD, pctinfo:DWORD
  82.         ; E_NOTIMPL
  83.         mov     eax,0x80000001
  84.         ret
  85. endp
  86.  
  87. ;----------------------------------------------------------------------------
  88. ; Заглушка для метода GetTypeInfo
  89. ;----------------------------------------------------------------------------
  90. proc IWebBrowserEvents_GetTypeInfo pthis:DWORD, iTInfo:DWORD,\
  91.         lcid:DWORD, ppTInfo:DWORD
  92.  
  93.         ; E_NOTIMPL
  94.         mov     eax,0x80000001
  95.         ret
  96. endp
  97.  
  98. ;----------------------------------------------------------------------------
  99. ; Заглушка для метода GetIDsOfNames
  100. ;----------------------------------------------------------------------------
  101. proc IWebBrowserEvents_GetIDsOfNames pthis:DWORD, riid:DWORD,\
  102.         rgszNames:DWORD, cNames:DWORD, lcid:DWORD, rgDispId:DWORD
  103.  
  104.         ; S_OK
  105.         xor     eax,eax
  106.         ret
  107. endp
  108.  
  109. ;----------------------------------------------------------------------------
  110. ; Основной обработчик событий
  111. ;----------------------------------------------------------------------------
  112. proc IWebBrowserEvents_Invoke pthis:DWORD, dispIdMember:DWORD,\
  113.         riid:DWORD, lcid:DWORD, wFlags:DWORD, pDispParams:DWORD,\
  114.         pVarResult:DWORD, pExcepInfo:DWORD, puArgErr:DWORD
  115.  
  116.         ; Пришло событие DISPID_DOCUMENTCOMPLETE?
  117.         cmp     [dispIdMember],DISPID_DOCUMENTCOMPLETE
  118.         jne     @f
  119.  
  120.         pusha
  121.         invoke  MessageBox,0,szText,szTitle,0
  122.         popa
  123. @@:
  124.         ; S_OK
  125.         xor     eax,eax
  126.         ret
  127. endp
  1. ; Настроить структуру IWebBrowserEvents для браузера
  2. mov     [WebBrowserEvents.QueryInterface],IWebBrowserEvents_QueryInterface
  3. mov     [WebBrowserEvents.AddRef],IWebBrowserEvents_AddRef
  4. mov     [WebBrowserEvents.Release],IWebBrowserEvents_Release
  5. mov     [WebBrowserEvents.GetTypeInfoCount],IWebBrowserEvents_GetTypeInfoCount
  6. mov     [WebBrowserEvents.GetTypeInfo],IWebBrowserEvents_GetTypeInfo
  7. mov     [WebBrowserEvents.GetIDsOfNames],IWebBrowserEvents_GetIDsOfNames
  8. mov     [WebBrowserEvents._Invoke],IWebBrowserEvents_Invoke
  9.  
  10. ; Заполнить указатель на структуру
  11. mov     [pWebBrowserEvents],WebBrowserEvents
Во-вторых, заполненную структуру надо подключить к интерфейсу объекта браузера. Для этого можно воспользоваться методом Advise интерфейса IConnectionPoint.
  1.         ; Запросить интерфейс IConnectionPointContainer у объекта браузера
  2.         mov     eax,[pBrowser]
  3.         mov     eax,[eax]
  4.         stdcall dword [eax+IWebBrowser2.QueryInterface],[pBrowser],\
  5.                 IID_IConnectionPointContainer,cPointContainer
  6.  
  7.         ; Найти точку соединения с DWebBrowserEvents2
  8.         mov     eax,[cPointContainer]
  9.         mov     eax,[eax]
  10.         stdcall dword [eax+IConnectionPointContainer.FindConnectionPoint],\
  11.                 [cPointContainer],\
  12.                 IID_DWebBrowserEvents2,cPoint
  13.  
  14.         ; Подключить интерфейс к точке соединения
  15.         mov     [pCookie],Cookie
  16.  
  17.         mov     eax,[cPoint]
  18.         mov     eax,[eax]
  19.         stdcall dword [eax+IConnectionPoint.Advise],[cPoint],\
  20.                 pWebBrowserEvents,[pCookie]
Или, раз уж для взаимодействия объекта браузера с компонентами приложения используются ATL-функции, приведенный выше код можно заменить одной строчкой:
  1.         ; Подключить интерфейс к точке соединения
  2.         mov     [pCookie],Cookie
  3.  
  4.         invoke  AtlAdvise,[pBrowser],pWebBrowserEvents,\
  5.                 IID_DWebBrowserEvents2,[pCookie]
Отключить от точки соединения и прекратить обработку событий браузера можно вызовом метода Unadvise интерфейса IConnectionPoint, если для подключения был использован этот способ.
  1.         ; Отключиться от точки соединения
  2.         mov     eax,[cPoint]
  3.         mov     eax,[eax]
  4.         stdcall dword [eax+IConnectionPoint.Unadvise],[cPoint],[Cookie]
В случае использования для подключения ATL-функции, отключение выполняется также одной строчкой:
  1.         ; Отключиться от точки соединения
  2.         invoke  AtlUnadvise,[pBrowser],IID_DWebBrowserEvents2,[Cookie]
С точками подключения разобрались, переходим к самому вкусному, а именно к обработке событий браузера. Вся магия творится в реализованной нами функции метода _Invoke интерфейса IWebBrowserEvents. При любом событии этой функции передается полный набор данных, касающихся этого события. Идентификатор события приходит в параметре dispIdMember. В нашем случае достаточно обрабатывать DISPID_DOCUMENTCOMPLETE, это событие наступает, когда открываемая в браузере страница переходит в статус READYSTATE_COMPLETE, то есть полностью загружена. Это же событие происходит в случае, если пользователь, к примеру, открывает страницы по ссылкам внутри встроенного браузера. С отслеживанием статуса страницы по таймеру такие ситуации обработать гораздо сложнее. Естественно, одним только этим событием браузер не ограничивается, коды других событий можно посмотреть в заголовочном файле exdispid.h SDK.

Как видите, ничего страшного в обработке событий IWebBrowser нет. Кроме объекта браузера подобные функции наблюдателя можно прикрепить к отдельным элементам HTML-страницы и отслеживать, например, переход по ссылкам. Пока такой задачи не стоит, но искать нужные теги на странице мы уже умеем.

В приложении примеры программ с исходными текстами, которые реализуют обработку событий встроенного браузера описанными в статье способами.

Примеры программ с исходными текстами (FASM)Примеры программ с исходными текстами (FASM)

IWebBrowser2.Events.Demo.zip (10,149 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 495 | Комментариев: 0

Метки: Assembler, сеть, COM
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.0098 сек.) / Память: 4.5 Mb
Наверх