程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 直接訪問WebBrowser控件中的HTML源碼

直接訪問WebBrowser控件中的HTML源碼

編輯:關於.NET
  為了實現在自己的程序中顯示Html文檔,我們一般采用IE(Internet Explorer本文中簡稱為IE)發行時附帶的一個ActiveX控件WebBrowser。這個控件使用和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.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); 
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控件的Form的FormCreate事件裡調用此函數,初始化WebBrowser.Document對象。本文程序在Win NT + Delphi 5 環境下調試通過。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved