[Delphi]如何挂上IDocHostUIHandler接口实现?

为了更好地控制WebBrowser,我们可以在一个com对象中实现IDocHostUIHandler(和IDocHostUIHandler2)接口,并把这个接口实现挂到WebBrowser实例上去,成功挂接之后,我们就可以通过实现这些接口的com对象控制WebBrowser的行为方式及其外观了。

为了演示如何挂接COM对象,我们假设我们在窗体上放置了一个TWebBrowser实例WB,并且实例化了一个实现IDocHostUIHandler接口的对象IEObject。我们将分别演示通过TWebBrowser的ICustomDoc接口和IOleObject实现挂接。

1. 使用IOleObject接口

TWebBrowser对象在初始化时会向宿主查询其是否实现了IDocHostUIHandler接口,假如宿主实现了该接口的话,就会调用该接口的方法控制自己的行为和外观。因此我们只要在TWebBrowser初始化之前将实现IDocHostUIHandler的com对象注册为TWebBrower对象的宿主的话,就可以让TWebBrowser控件自身来查询IDocHostUIHandler接口了。

{code start}

procedure TMainForm.FormCreate(Sender: TObject);

var

Rect: TRect;

begin

//设置浏览器站点,设置之后浏览器将自动查询IDocHostUIHandler、IDocHostUIHandler2、

//IDocHostShowUI等接口

(WB.Application as IOleObject).SetClientSite(IEObject as IOleClientSite);

//本地激活浏览器控件

Rect := Self.GetClientRect;

(WB.Application as IOleObject).DoVerb(OLEIVERB_INPLACEACTIVATE, nil,

Self, 0, Self.Handle, Rect);

ManageConnection(True); //注册事件连接

WB.GoHome; //程序启动时导航到首页

end;

{code end}

2. 使用ICustomDoc接口

如果IEObject由于某种原因无法实现IOleClientSite的话,我们就不能简单地让TWebBrowser对象来查询其宿主的IDocHostUIHandler接口,我们必须显式地将实现该接口的对象赋给TWebBrowser的Document对象,ICustomDoc可以说就是为了这个目的而生的。

使用该方法的一个至关重要的问题是必须在TWebBrowser的Document对象建立的时候才可以调用其ICustomDoc接口,否则就会挂接失败,由于Navigate方法是异步执行的,因此我们不能像这样挂接:

{code start}

WB.GoHome; //or WB.Navigate('http://xxx");

(WB.Document as ICustomDoc).SetUIHandler(IEObject);

{code end}

这种挂接方式可能会生效,但是SetUIHiandler完全可能在Document对象建立之前就被调用,因此这不是一个好的途径,我们可以在TWebBrowser的OnDocumentComplete处理函数中进行挂接,这时候我们可以确保TWebBrowser的Document对象确确实实已经建立起来了,因此调用理论上讲可以100%成功。

除此之外,我们还可以这样做:

{code start}

WB.GoHome;

while (WB.ReadState <> READYSTATE_COMPLETE )

;

(WB.Document as ICustomDoc).SetUIHandler(IEObject);

{code end}

这样做同样可以达到我们的目的。缺点: 虽然这种方法可以达到挂接的目的,但是在实践中发现,由于WB是在装载文档完成之后才挂上IDocUIHandler接口实现的,因此第一次转载文档的时候是不会使用该接口来控制外观和行为的(没挂上当然就不知道怎么用了),因此必须在挂上之后再一次进行刷新才行。

附:由于Delphi本身缺少IDocHostUIHandler等接口的声明,如果要编译上述代码,你可以去IE&Delphi下载IEConst.pas。其中ICustomDoc接口声明不存在于该文件中,特声明如下:

{code start}

ICustomDoc = interface(IUnknown)

['{3050F3F0-98B5-11CF-BB82-00AA00BDCE0B}']

function SetUIHandler(const pUIHandler: IDocHostUIHandler): HRESULT; stdcall;

end;

{code end}