[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}