直接访问WebBrowser控件中的HTML源码

为了实现在自己的程序中显示HTML文档,我们一般采用IE(Internet Explorer本文中简称为IE)发行时附带的一个ActiveX控件TWebBrowser。这个控件使用和IE相同的内核,功能强大,并从Delphi5开始,正式得到Inprise公司的支持,取代了原来的那个THTML控件,成为Delphi中显示HTML文档的首选控件。

但是在实际编程过程中,我发现这个控件提供的功能有很多限制,比如对HTML文档的浏览,只能通过指定URL或文件名来实现,不能像以往使用THTML控件那样直接读写HTML源码。因此如果程序动态生成了一段HTML文本,就必须把文本内容先写到一个临时文件,然后再将此文件的文件名传递给WebBrowser控件,实现显示。走这一个弯路使程序响应速度受到很大影响,而且容易遗留下一些"垃圾"(临时文件)。

在考察了一些使用了WebBrowser控件的程序后,我发现大部分程序,如著名国产软件FoxMail,都是使用的通过临时文件传递HTML文档的方法;但一些国外的软件,如MS自己的OutLook Express则不存在这个问题,而因为其无需产生临时文件,因此对HTML文档的显示速度明显超过Foxmail。

其实,WebBrowser控件中的Document对象,这个对象提供了一个IPersistStreamInit接口,通过此接口,我们可以方便地实现对HTML源码的读写。

以下是IPersistStreamInit接口的相关定义及说明:
{ IPersistStream interface }

{$EXTERNALSYM IPersistStream}
IPersistStream = interface(IPersist)
['{00000109-0000-0000-C000-000000000046}']
function IsDirty: HResult; stdcall;    // 最后一次存盘后是否被修改
function Load(const stm: IStream): HResult; stdcall;// 从流中载入
function Save(const stm: IStream;fClearDirty: BOOL): HResult; stdcall;// 保存到流
function GetSizeMax(out cbSize: Largeint):HResult; stdcall; // 取得保存所需空间大小
end;

{ IPersistStreamInit interface }

{$EXTERNALSYM IPersistStreamInit}
IPersistStreamInit = interface(IPersistStream)
['{7FD52380-4E07-101B-AE2D-08002B2EC713}']
function InitNew: HResult; stdcall; // 初始化
end;

首先来实现写,因为这是最迫切的要求:
procedure SetHtml(const WebBrowser: TWebBrowser; const Html: string);
var
  Stream: IStream;
  hHTMLText: HGLOBAL;
  psi: IPersistStreamInit;
begin
  if not Assigned(WebBrowser) then Exit;
  WebBrowser.Navigate('about:blank ');
  if not Assigned(WebBrowser.Document) then Exit;
  hHTMLText := GlobalAlloc(GPTR, Length(Html) + 1);
  if 0 = hHTMLText then RaiseLastWin32Error;
  CopyMemory(Pointer(hHTMLText), PChar(Html), Length(Html));
  OleCheck(CreateStreamOnHGlobal(hHTMLText, True, Stream));
  try
    OleCheck(WebBrowser.Document.QueryInterface(IPersistStreamInit, psi));
    try
      OleCheck(psi.InitNew);
      Application.ProcessMessages;
      OleCheck(psi.Load(Stream));
    finally
      psi := nil;
    end;
  finally
    Stream := nil;
  end;
end;

首先,此过程需要的两个参数,WebBrowser是显示目的控件,Html是需要显示的HTML源码;然后,先检查WebBrowser.Document对象是否有效,无效则退出;接着在系统全局堆里分配一块内存,将需要显示的HTML源码复制进去。这是因为下一步需要建立一个WebBrowser控件可以读取的流。GlobalAlloc函数的参数GPTR表示需要分配一块固定的以0初始化过的内存区域,如果分配失败则返回0,则通过RaiseLastWin32Error函数引发一个异常,提示用户;然后用CreateStreamOnHGlobal函数建立一个基于全局堆内存块的流,第二个参数如果为True则流在释放时自动释放所占全局堆内存。如果建立成功则此流和刚刚建立的内存块共用同一块内存区域。接着用WebBrowser.Document.QueryInterface函数建立一个IPersistStreamInit接口。然后就可以直接使用此接口,psi.InitNew初始化状态;psi.Load(Stream)从流中载入HTML源码。
至此,以Html参数指定的HTML源码就在WebBrowser参数指定的控件中显示出来。

值得注意的是,每个关于COM接口的函数调用,也就是那些返回类型为HResult的函数,都必须以OleCheck包装,因为一个不检查返回状态的COM接口操作实在太危险了;此外接口的释放,虽然Delphi可以在后台自动完成,但作为一个好的编程习惯,还是应该显式地手工释放,释放只需将接口设为nil即可。

接着来实现HTML源码的读:
function GetHtml(const WebBrowser: TWebBrowser): string;
const
  BufSize = $10000;
var
  Size: Int64;
  Stream: IStream;
  hHTMLText: HGLOBAL;
  psi: IPersistStreamInit;
begin
  if not Assigned(WebBrowser.Document) then Exit;
  OleCheck(WebBrowser.Document.QueryInterface(IPersistStreamInit, psi));
  try
//    OleCheck(psi.GetSizeMax(Size));
    hHTMLText := GlobalAlloc(GPTR, BufSize);
    if 0 = hHTMLText then RaiseLastWin32Error;
    OleCheck(CreateStreamOnHGlobal(hHTMLText, True, Stream));
    try
      OleCheck(psi.Save(Stream, False));
      Size := StrLen(PChar(hHTMLText));
      SetLength(Result, Size);
      CopyMemory(PChar(Result), Pointer(hHTMLText), Size);
    finally
      Stream := nil;  
    end;
  finally
    psi := nil;
  end;
end;

此函数有一个参数WebBrowser指定从那个控件读取HTML源码,返回一个字符串为此控件中的HTML源码。首先还是要先检查WebBrowser.Document对象是否有效,无效则退出;然后取得IPersistStreamInit接口;接着取得HTML源码的大小:本来应该使用IPersistStreamInit接口的GetSizeMax函数,但在我的机器上测试,这个函数范围值衡为0,无效。因此只能先定义一个足够大的缓冲区,如BufSize = $10000字节(注意此缓冲区应该足够大);然后同样地分配全局堆内存块,建立流,然后将HTML文本写到流中。因为此HTML文本在流中是以#0结尾的字符串,因此可以用Size := StrLen(PChar(hHTMLText))取得实际长度,用SetLength(Result, Size);设置返回字符串长度为HTML源码实际长度,最后复制字符串到返回字符串中。
至此,直接访问WebBrowser控件中的HTML源码所需的两个函数全部解析完毕。

不过需要注意的时,在使用这两个函数前,最好对WebBrowser.Document对象进行初始化。下面提供一个函数,通过显示一个空白页面实现WebBrowser.Document对象初始化。

procedure ShowBlankPage(WebBrowser:
TWebBrowser);
var
  URL: OleVariant;
begin
  URL := 'about:blank';
  WebBrowser.Navigate2(URL);
end;


(*//
标题:显示超文本
说明:在WebBrowser直接载入流,不通过文件
设计:Zswang
日期:2002-06-06
支持:wjhu111@21cn.com
//*)

///Begin   Source
uses   ActiveX;

function   ShowHtml(mWebBrowser:   TWebBrowser;   mStrings:   TStrings):   Boolean;
var
    vMemoryStream:   TMemoryStream;
begin
    Result   :=   False;
    if   not   (Assigned(mStrings)   and   Assigned(mWebBrowser))   then   Exit;
    mWebBrowser.Navigate( 'about:blank ');
    if   not   Assigned(mWebBrowser.Document)   then   Exit;
    vMemoryStream   :=   TMemoryStream.Create;
    try
        mStrings.SaveToStream(vMemoryStream);
        try
            vMemoryStream.Position   :=   0;
            Application.ProcessMessages;   //   :)
            (mWebBrowser.Document   as   IPersistStreamInit).Load(
                TStreamAdapter.Create(vMemoryStream));
        except
            Exit;
        end;
    finally
        vMemoryStream.Free;
    end;
    Result   :=   True;
end;   {   ShowHtml   }
///End   Source

///Begin   Demo
procedure   TForm1.Button1Click(Sender:   TObject);
begin
    ShowHtml(WebBrowser1,   Memo1.Lines);
end;

procedure   TForm1.FormCreate(Sender:   TObject);
begin
    Memo1.Text   :=
' <html> '#13#10   +
' <body   bkcolor=#FF00FF> <b> Hello   Worlds! </b> </body> '#13#10   +
' </html> '#13#10;
end;
///End   Demo
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebbrowserEx模仿IE实例源码 Private WithEvents mobjWebDoc As MSHTML.HTMLDocument Private WithEvents MouseEvent As CMouseHook Private WithEvents KeyboardEvent As CKeyboardHook Private WithEvents frmTopParent As VB.Form Private m_Documents As Collection 'HTML Documents collection Private m_Frames As Collection 'HTML Frames collection '------------------------------------------------------------------------------- ' Webbrowser naviagtion events '------------------------------------------------------------------------------- ' Event IntializeBeforeGoHome(Cancel As Boolean) Event StatusTextChange(ByVal Text As String) Event TitleChange(ByVal Text As String) Event NewDocumentStart(ByVal WebDoc As HTMLDocument, ByVal URL As String, ByVal IsTargetedToFrame As Boolean, ByVal TargetFrameName As String, Cancel As Boolean) Event NewDocumentComplete(ByVal WebDoc As HTMLDocument, ByVal URL As String, ByVal IsTargetedToFrame As Boolean, ByVal TargetFrameName As String) Event BeforeNavigate2(ByVal WebDoc As HTMLDocument, ByVal URL As String, Flags As Variant, TargetFrameName As Variant, PostData As Variant, Headers As Variant, Cancel As Boolean) Event NavigateComplete2(ByVal WebDoc As HTMLDocument, ByVal URL As String) Event DocumentComplete(ByVal WebDoc As HTMLDocument, ByVal URL As String) Event BeforeNewWindow2(ByVal URL As String, NewBrowser As Object, Cancel As Boolean) '------------------------------------------------------------------------------- ' User control-wide mouse events '------------------------------------------------------------------------------- ' Event UserControlMouseUp(ByVal Control As Object, ByVal HWnd As Long, Button As Integer, Shift As Integer, X As Single, Y As Single, Cancel As Boolean) Event UserControlMouseMove(ByVal Control As Object, ByVal HWnd As Long, Button As Integer, Shift As Integer, X As Single, Y As Single, Cancel As Boolean) Event UserControlMouseDown(ByVal Control As Object, ByVal HWnd As Long, Button As Integer, Shift As Integer, X As Single, Y As Single, Cancel As Boolean) '------------------------------------------------------------------------------- ' WebBrowser mouse events '------------------------------------------------------------------------------- ' Event WebBrowserDblClick(Cancel As Boolean) Event WebBrowserMouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single, Cancel As Boolean) Event WebBrowserMouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single, Cancel As Boolean) Event WebBrowserMouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single, Cancel As Boolean) Event WebBrowserMouseDownContextMenu(ByVal IsMouseOnLink As Boolean, ByVal URL As String, ByVal SelText As String, Cancel As Boolean) Event WebBrowserMouseUpContextMenu(ByVal IsMouseOnLink As Boolean, ByVal URL As String, ByVal SelText As String, Cancel As Boolean) '------------------------------------------------------------------------------- ' WebBrowser keyboard events '------------------------------------------------------------------------------- ' Event WebBrowserKeyDown(KeyCode As Integer, Shift As Integer) Event WebBrowserKeyUp(KeyCode As Integer, Shift As Integer) '------------------------------------------------------------------------------- ' Go button keyboard events '------------------------------------------------------------------------------- ' Event GoButtonKeyDown(KeyCode As Integer, Shift As Integer) Event GoButtonKeyUp(KeyCode As Integer, Shift As Integer) '------------------------------------------------------------------------------- ' Address bar keyboard events (combo box) '------------------------------------------------------------------------------- ' Event AddressBarContextMenu(Cancel As Boolean) Event AddressBarKeyDown(KeyCode As Integer, Shift As Integer) Event AddressBarKeyUp(KeyCode As Integer, Shift As Integer) '------------------------------------------------------------------------------- ' Statusbar keyboard events '------------------------------------------------------------------------------- ' Event StatusBarKeyDown(KeyCode As Integer, Shift As Integer) Event StatusBarKeyUp(KeyCode As Integer, Shift As Integer) '------------------------------------------------------------------------------- ' Statusbar mouse events '------------------------------------------------------------------------------- ' Event StatusBarPanelClick(Panel As MSComctlLib.Panel) Event StatusBarPanelDblClick(Panel As MSComctlLib.Panel) Event StatusBarMouseMove(Panel As MSComctlLib.Panel, Button As Integer, Shift As Integer, X As Single, Y As Single) Event StatusBarMouseDown(Panel As MSComctlLib.Panel, Button As Integer, Shift As Integer, X As Single, Y As Single) Event StatusBarMouseUp(Panel As MSComctlLib.Panel, Button As Integer, Shift As Integer, X As Single, Y As Single) Private mstrStatusText As String 'Webrrowser status text Private mlngWBHwnd As Long 'Webbrowser handle Private mHwndComboEdit As Long 'Combo edit box handle Private mobjTopParent As VB.Form 'Reference to Top parent form Private mbRunMode As Boolean 'Run/Develope mode detection variable Private newX As Single 'Variables that contained the converted x, y coordinates Private newY As Single Private mhwndTopParent As Long 'Top parent form handle Private mstrClickedLinkURL As String 'Click-on url Private mstrNavigate2URL As String 'Navigation start url Private mstrNavigatedURL As String 'Navigated url Private mstrTargetFrameName As String 'Naviation target frame Const m_def_PopupWindowAllowed = True Const m_def_OpenHomePageAtStart = True Const m_def_AddressBarVisible = True Const m_def_StatusBarVisible = True Const m_def_MouseEventEnabled = True Const m_def_KeyboardEventEnabled = True Private m_AddressBarVisible As Boolean Private m_PopupWindowAllowed As Boolean Private m_OpenHomePageAtStart As Boolean Private m_StatusBarVisible As Boolean Private m_MouseEventEnabled As Boolean Private m_KeyboardEventEnabled As Boolean '------------------------------------------------------------------------------- ' TopParent '------------------------------------------------------------------------------- ' Get the top parent form of the user control Public Property Get TopParent() As Object On Error Resume Next If mobjTopParent Is Nothing Then Dim objParent As Object Set objParent = UserControl.Parent Do While Not TypeOf objParent Is VB.Form Set objParent = objParent.Parent Loop Set mobjTopParent = objParent Set objParent = Nothing End If Set TopParent = mobjTopParent End Property
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值