zoukankan      html  css  js  c++  java
  • 接收IWebBrowser2的自动化事件

    OLE自动化的控制方有时要从受控方接收事件通知。比如WebBrowser的OnNavagiteComplete,OnDocumentComplete等事件。OLE对象需要实现IConnectionPointContainer接口。IConnectionPointContainer和其它几个跟自动化事件相关的接口定义如下:

    IEnumConnections = interface
        ['{B196B287-BAB4-101A-B69C-00AA00341D07}']
        function Next(celt: Longint; out elt;
          pceltFetched: PLongint): HResult; stdcall;
        function Skip(celt: Longint): HResult; stdcall;
        function Reset: HResult; stdcall;
        function Clone(out Enum: IEnumConnections): HResult; stdcall;
    end;

    { IConnectionPoint interface }

    {$EXTERNALSYM IConnectionPoint}
    IConnectionPoint = interface
        ['{B196B286-BAB4-101A-B69C-00AA00341D07}']
        function GetConnectionInterface(out iid: TIID): HResult; stdcall;
        function GetConnectionPointContainer(out cpc: IConnectionPointContainer): HResult;
          stdcall;
        function Advise(const unkSink: IUnknown; out dwCookie: Longint): HResult; stdcall;
        function Unadvise(dwCookie: Longint): HResult; stdcall;
        function EnumConnections(out Enum: IEnumConnections): HResult; stdcall;
    end;

    { IConnectionPointContainer interface }
    {$EXTERNALSYM IConnectionPointContainer}
    IConnectionPointContainer = interface
        ['{B196B284-BAB4-101A-B69C-00AA00341D07}']
        function EnumConnectionPoints(out Enum: IEnumConnectionPoints): HResult;
          stdcall;
        function FindConnectionPoint(const iid: TIID;
          out cp: IConnectionPoint): HResult; stdcall;
    end;

    { IEnumConnectionPoints interface }

    {$EXTERNALSYM IEnumConnectionPoints}
    IEnumConnectionPoints = interface
        ['{B196B285-BAB4-101A-B69C-00AA00341D07}']
        function Next(celt: Longint; out elt;
          pceltFetched: PLongint): HResult; stdcall;
        function Skip(celt: Longint): HResult; stdcall;
        function Reset: HResult; stdcall;
        function Clone(out Enum: IEnumConnectionPoints): HResult;
          stdcall;
    end;

    需要接收自动化事件通知时,可以用InterfaceConnect注册:

    procedure InterfaceConnect(const Source: IUnknown; const IID: TGUID;
    const Sink: IUnknown; var Connection: Longint);
    var
    CPC: IConnectionPointContainer;
    CP: IConnectionPoint;
    begin
    Connection := 0;
    if Source.QueryInterface(IConnectionPointContainer, CPC)=S_OK then
        if CPC.FindConnectionPoint(IID, CP)=S_OK then
          CP.Advise(Sink, Connection);
    end;

    其中Source为受控方OLE对象的接口。IID是事件连接点的GUID。一个OLE对象可能有多个事件连接点,比如IWebBrowser2有个时间连接点为:
      
        WebBrowserEventId : TGUID='{34A715A0-6587-11D0-924A-0020AFC7AC4D}';

    Sink就是接收事件通知的对象的接口了,这个对象至少需要实现IUnknown和IDispatch接口。当事件触发时,事件接收者的Invoke方法会被调用:

    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;Flags: Word; var Params;
    VarResult, ExcepInfo, ArgErr: Pointer): HResult; virtual; stdcall;

    DispID为事件的编号,可以从自动化对象的事件接口的声明里找到这个编号。比如IWebBrowser的事件声明

       DWebBrowserEvents2 = dispinterface
        ['{34A715A0-6587-11D0-924A-0020AFC7AC4D}']
        procedure StatusTextChange(const Text: WideString); dispid 102;
        procedure ProgressChange(Progress: Integer; ProgressMax: Integer); dispid 108;
        procedure CommandStateChange(Command: Integer; Enable: WordBool); dispid 105;
        procedure DownloadBegin; dispid 106;
        procedure DownloadComplete; dispid 104;
        procedure TitleChange(const Text: WideString); dispid 113;
        procedure PropertyChange(const szProperty: WideString); dispid 112;
        procedure BeforeNavigate2(const pDisp: IDispatch; var URL: OleVariant; var Flags: OleVariant;
                                  var TargetFrameName: OleVariant; var PostData: OleVariant;
                                  var Headers: OleVariant; var Cancel: WordBool); dispid 250;
        procedure NewWindow2(var ppDisp: IDispatch; var Cancel: WordBool); dispid 251;
        procedure NavigateComplete2(const pDisp: IDispatch; var URL: OleVariant); dispid 252;
        procedure DocumentComplete(const pDisp: IDispatch; var URL: OleVariant); dispid 259;
        procedure OnQuit; dispid 253;
        procedure OnVisible(Visible: WordBool); dispid 254;
        procedure OnToolBar(ToolBar: WordBool); dispid 255;
        procedure OnMenuBar(MenuBar: WordBool); dispid 256;
        procedure OnStatusBar(StatusBar: WordBool); dispid 257;
        procedure OnFullScreen(FullScreen: WordBool); dispid 258;
        procedure OnTheaterMode(TheaterMode: WordBool); dispid 260;
    end;

    方法声明后面dispid数字就是DispID。所以如果接收到IWebBrowser2的DispID为259的通知,就表明DocumentComplete事件发生了。

    Invoke的Params变参包含特定事件的附加信息,或者叫做事件参数。他是一个TDispParams结构:

    tagDISPPARAMS = record
        rgvarg: PVariantArgList;//Variant类型的数组。
        rgdispidNamedArgs: PDispIDList;
        cArgs: Longint; //参数个数
        cNamedArgs: Longint;
    end;

    对于IWebBrowser2的DocumentComplelte事件,rgvarg[1]就是发出此事件通知的IWebBrowser2接口。请注意,一个内嵌框架下载完成也会触发DocumentComplelte事件,要判断是否整个网页都下载完毕了可以用以下方法(TEventDispatch是我写的一个接收自动化事件通知的类):

    function TEventDispatch.Invoke(DispID: Integer; const IID: TGUID;
    LocaleID: Integer; Flags: Word; var Params;
    VarResult, ExcepInfo, ArgErr: Pointer): HResult;
    var
    vPDispParams: PDispParams;
    ib:IWebBrowser2;
    begin
    vPDispParams := PDispParams(@Params);
    if DispID=259 then
    begin
        if (IDispatch(OleVariant(vPDispParams.rgvarg[1])).QueryInterface(IID_IWebBrowser2,ib)=0) and (ib.Container=nil) then
        begin
          //整个网页下载完成
        end
        else
        begin
          //某个内嵌框架网页下载完成了,但是整个网页没有完成
        end;
    end;
    Result:= S_OK;
    end;

    对于IWebBrowser的其它事件我就不再赘述了,可以参考Delphi的TWebBrowser的代码。
  • 相关阅读:
    验证 Email
    取系统时间
    DbHelperSQL.cs
    显示BYTE流图片
    [原]c# 读取文本文件(txt)
    数据库文件组和文件的作用
    Transact—SQL
    m_pMainWnd
    sql server 2005 window 身份证验证模式与SQL Server身份验证
    WM_CLOSE WM_DESTROY WM_QUIT
  • 原文地址:https://www.cnblogs.com/MaxWoods/p/1371123.html
Copyright © 2011-2022 走看看