|
Page 1 of 2 In this article, I will discuss about technique to catch events happened in a web browser. I wrote this article to answer a question posted by Johan Max at Delphindo about how to get notified when an anchor tag in a HTML document is clicked and also how to retrieve URL pointed by the anchor.
Of course we still use our favourite tool. Delphi. This tutorial only assumes web browser is IE, for other web browsers, this technique may not work. Source code is available for download on Download-Delphi Programming section.
Required unit.
First, import ActiveX MSHTML. If you already have MSHTML.pas or MSHTML_TLB.pas file on your system (look for it in Imports directory in your Delphi installation directory), it means you are ready to continue reading this article.
Step by step to monitor web browser events.
- Create event sink implementation.
- Load HTML document until it is complete.
- Get HTML elements to monitor.
- Connect event sink to HTML elements.
If you reach fourth step, then your application is ready to catch web browser events. When you want to stop monitoring events, last step is
Ok, let us discuss it one by one.
Creating event sink implementation
Event sink must be derived from IDispatch interface, because Invoke() will be called each time event occur. Following code snippet is IDispatch declaration (unit system.pas).
IDispatch = interface(IUnknown) ['{00020400-0000-0000-C000-000000000046}'] function GetTypeInfoCount(out Count: Integer): HResult; stdcall; function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; end;
All four methods must be implemented. IDispatch is derived from IUnknown, so we also need to implement IUnknown method. To avoid need to implement IUnknown, we can derived our implementation class from TInterfacedObject. Please note that, except Invoke(), other methods are less relevant to our goal, so we can set it unimplemented. Code snippet is as follow:
unit ueventsink;
interface uses classes,windows,sysutils,mshtml;
type IEventSink=interface(IDispatch) ['{AC8E45D3-DABB-4DC0-AD94-D53FA67DD78A}'] procedure SetOnClick(const Value: THTMLElementOnClick); function GetOnClick: THTMLElementOnClick; procedure SetWebBrowser(const Value: IWebBrowser2); function GetWebBrowser: IWebBrowser2;
property OnClick:THTMLElementOnClick read GetOnClick write SetOnClick; property WebBrowser:IWebBrowser2 read GetWebBrowser write SetWebBrowser; end;
TEventSink=class(TInterfacedObject,IDispatch,IEventSink) public
procedure SetOnClick(const Value: THTMLElementOnClick); function GetOnClick: THTMLElementOnClick; procedure SetWebBrowser(const Value: IWebBrowser2); function GetWebBrowser: IWebBrowser2;
function GetTypeInfoCount(out Count: Integer): HResult; stdcall; function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
end; implementation
{ TEventSink }
function TEventSink.GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; begin result:=E_NOTIMPL; end;
function TEventSink.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; begin result:=E_NOTIMPL; end;
function TEventSink.GetTypeInfoCount(out Count: Integer): HResult; begin result:=E_NOTIMPL; end;
function TEventSink.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; begin
end;
end.
We will only pay attention to Invoke() implementation. Ok, now add an event property to TEventSink class.
type THTMLElementOnClick=procedure (Sender:TObject; Element:IHTMLElement; var cancel:boolean) of object;
Add in published part, following code
property OnClick:THTMLElementOnClick;
Press Shift+Ctrl+C to complete class declaration. This is Invoke() implementation.
function TEventSink.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; var cancel:boolean; begin case dispID of -600:begin if Assigned(FOnClick) then begin cancel:=false; FOnClick(self,nil,cancel); end; end; end; result:=S_OK; end;
|