直接访问WebBrowserControl控件中
![](/icons/64035de.gif)
HTML源码
华中师范大学
卢小海
---- 为了实现在自己
![](/icons/64035de.gif)
![](/icons/64035chengxu.gif)
中显示HTML文档
![](/icons/64035dou.gif)
我们
![](/icons/64035yi.gif)
般采用IE(Internet Explorer本文中简称为IE)发行时附带
![](/icons/64035de.gif)
![](/icons/64035yi.gif)
个ActiveXControl控件TWebBrowser
![](/icons/64035dou2.gif)
这个Control控件使用和IE相同
![](/icons/64035de.gif)
内核
![](/icons/64035dou.gif)
功能强大
![](/icons/64035dou.gif)
并从Delphi5开始
![](/icons/64035dou.gif)
正式得到Inprise公司
![](/icons/64035de.gif)
支持
![](/icons/64035dou.gif)
取代了原来
![](/icons/64035de.gif)
那个THTMLControl控件
![](/icons/64035dou.gif)
成为Delphi中显示HTML文档
![](/icons/64035de.gif)
首选Control控件
---- 但是在实际编程过程中
![](/icons/64035dou.gif)
我发现这个Control控件提供
![](/icons/64035de.gif)
功能有很多限制
![](/icons/64035dou.gif)
比如对HTML文档
![](/icons/64035de.gif)
浏览
![](/icons/64035dou.gif)
只能通过指定URL或文件名来实现
![](/icons/64035dou.gif)
不能像以往使用THTMLControl控件那样直接读写HTML源码
![](/icons/64035dou2.gif)
因此如果
![](/icons/64035chengxu.gif)
动态生成了
![](/icons/64035yi.gif)
段HTML文本
![](/icons/64035dou.gif)
就必须把文本内容先写到
![](/icons/64035yi.gif)
个临时文件
![](/icons/64035dou.gif)
然后再将此文件
![](/icons/64035de.gif)
文件名传递给WebBrowserControl控件
![](/icons/64035dou.gif)
实现显示
![](/icons/64035dou2.gif)
走这
![](/icons/64035yi.gif)
个弯路使
![](/icons/64035chengxu.gif)
响应速度受到很大影响
![](/icons/64035dou.gif)
而且容易遗留下
![](/icons/64035yi.gif)
些\"垃圾\"(临时文件)
---- 在考察了
![](/icons/64035yi.gif)
些使用了WebBrowserControl控件
![](/icons/64035de.gif)
![](/icons/64035chengxu.gif)
后
![](/icons/64035dou.gif)
我发现大部分
![](/icons/64035chengxu.gif)
![](/icons/64035dou.gif)
如著名国产软件SoftwareFoxMail
![](/icons/64035dou.gif)
都是使用
![](/icons/64035de.gif)
通过临时文件传递HTML文档
![](/icons/64035de.gif)
思路方法;但
![](/icons/64035yi.gif)
些国外
![](/icons/64035de.gif)
软件Software
![](/icons/64035dou.gif)
如MS自己
![](/icons/64035de.gif)
OutLook Express则不存在这个问题
![](/icons/64035dou.gif)
而
![](/icons/64035yinwei.gif)
其无需产生临时文件
![](/icons/64035dou.gif)
因此对HTML文档
![](/icons/64035de.gif)
显示速度明显超过Foxmail
---- 为此
![](/icons/64035dou.gif)
我查阅了
![](/icons/64035yi.gif)
些相关资料
![](/icons/64035dou.gif)
最后在网友
![](/icons/64035de.gif)
帮助下找到了实现直接访问WebBrowserControl控件中
![](/icons/64035de.gif)
HTML源码
![](/icons/64035de.gif)
思路方法
![](/icons/64035dou2.gif)
在此要特别感谢白云黄鹤BBS(bbs.whnet.edu.cn)上
![](/icons/64035de.gif)
网友AngleFalls提供线索
---- 其实
![](/icons/64035dou.gif)
WebBrowserControl控件中
![](/icons/64035de.gif)
Document对象
![](/icons/64035dou.gif)
这个对象提供了
![](/icons/64035yi.gif)
个IPersistStreamInit接口
![](/icons/64035dou.gif)
通过此接口
![](/icons/64035dou.gif)
我们可以方便地实现对HTML源码
![](/icons/64035de.gif)
读写
---- 以下是IPersistStreamInit接口
![](/icons/64035de.gif)
相关定义及介绍说明:
{ IPersistStream
![](/icons/64035int.gif)
erface }
{$EXTERNALSYM IPersistStream}
IPersistStream =
![](/icons/64035int.gif)
erface(IPersist)
[\'{00000109-0000-0000-C000-000000000046}\']
function IsDirty: HResult; stdcall;
// 最后
![](/icons/64035yi.gif)
次存盘后是否被修改
function Load(const stm: IStream): HResult; stdcall;
// 从流中载入
function Save(const stm: IStream;
fClearDirty: BOOL): HResult; stdcall;
// 保存到流
function GetSizeMax(out cbSize: Large
![](/icons/64035int.gif)
):
HResult; stdcall; // 取得保存所需空间大小
end;
{ IPersistStreamInit
![](/icons/64035int.gif)
erface }
{$EXTERNALSYM IPersistStreamInit}
IPersistStreamInit =
![](/icons/64035int.gif)
erface(IPersistStream)
[\'{7FD52380-4E07-101B-AE2D-08002B2EC713}\']
function InitNew: HResult; stdcall; //
![](/icons/64035chushi.gif)
化
end;
首先来实现写
![](/icons/64035dou.gif)
![](/icons/64035yinwei.gif)
这是最迫切
![](/icons/64035de.gif)
要求:
procedure SetHtml(const WebBrowser:
TWebBrowser; const Html:
![](/icons/64035string.gif)
);
var
Stream: IStream;
hHTMLText: HGLOBAL;
psi: IPersistStreamInit;
begin
![](/icons/64035if.gif)
not Assigned(WebBrowser.Document) then Exit;
hHTMLText := GlobalAlloc(GPTR, Length(Html) + 1);
![](/icons/64035if.gif)
0 = hHTMLText then RaiseLastWin32Error;
CopyMemory(Po
![](/icons/64035int.gif)
er(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;
---- 首先
![](/icons/64035dou.gif)
此过程需要
![](/icons/64035de.gif)
两个参数
![](/icons/64035dou.gif)
WebBrowser是显示目
![](/icons/64035de.gif)
Control控件
![](/icons/64035dou.gif)
Html是需要显示
![](/icons/64035de.gif)
HTML源码;然后
![](/icons/64035dou.gif)
先检查WebBrowser.Document对象是否有效
![](/icons/64035dou.gif)
无效则退出;接着在系统全局堆里分配
![](/icons/64035yi.gif)
块内存
![](/icons/64035dou.gif)
将需要显示
![](/icons/64035de.gif)
HTML源码复制进去
![](/icons/64035dou2.gif)
这是
![](/icons/64035yinwei.gif)
下
![](/icons/64035yi.gif)
步需要建立
![](/icons/64035yi.gif)
个WebBrowserControl控件可以读取
![](/icons/64035de.gif)
流
![](/icons/64035dou2.gif)
GlobalAlloc
![](/icons/64035hanshu.gif)
![](/icons/64035de.gif)
参数GPTR表示需要分配
![](/icons/64035yi.gif)
块固定
![](/icons/64035de.gif)
以0
![](/icons/64035chushi.gif)
化过
![](/icons/64035de.gif)
内存区域
![](/icons/64035dou.gif)
如果分配失败则返回0
![](/icons/64035dou.gif)
则通过RaiseLastWin32Error
![](/icons/64035hanshu.gif)
引发
![](/icons/64035yi.gif)
个异常
![](/icons/64035dou.gif)
提示用户;然后用CreateStreamOnHGlobal
![](/icons/64035hanshu.gif)
建立
![](/icons/64035yi.gif)
个基于全局堆内存块
![](/icons/64035de.gif)
流
![](/icons/64035dou.gif)
第 2个参数如果为True则流在释放时自动释放所占全局堆内存
![](/icons/64035dou2.gif)
如果建立成功则此流和刚刚建立
![](/icons/64035de.gif)
内存块共用同
![](/icons/64035yi.gif)
块内存区域
![](/icons/64035dou2.gif)
接着用WebBrowser.Document.QueryInterface
![](/icons/64035hanshu.gif)
建立
![](/icons/64035yi.gif)
个IPersistStreamInit接口
![](/icons/64035dou2.gif)
然后就可以直接使用此接口
![](/icons/64035dou.gif)
psi.InitNew
![](/icons/64035chushi.gif)
化状态;psi.Load(Stream)从流中载入HTML源码
---- 至此
![](/icons/64035dou.gif)
以Html参数指定
![](/icons/64035de.gif)
HTML源码就在WebBrowser参数指定
![](/icons/64035de.gif)
Control控件中显示出来
---- 值得注意
![](/icons/64035de.gif)
是
![](/icons/64035dou.gif)
每个有关COM接口
![](/icons/64035de.gif)
![](/icons/64035hanshu.gif)
![](/icons/64035diaoyong.gif)
![](/icons/64035dou.gif)
也就是那些返回类型为HResult
![](/icons/64035de.gif)
![](/icons/64035hanshu.gif)
![](/icons/64035dou.gif)
都必须以OleCheck包装
![](/icons/64035dou.gif)
![](/icons/64035yinwei.gif)
![](/icons/64035yi.gif)
个不检查返回状态
![](/icons/64035de.gif)
COM接口操作实在太危险了;此外接口
![](/icons/64035de.gif)
释放
![](/icons/64035dou.gif)
虽然Delphi可以在后台自动完成
![](/icons/64035dou.gif)
但作为
![](/icons/64035yi.gif)
个好
![](/icons/64035de.gif)
编程习惯
![](/icons/64035dou.gif)
还是应该显式地手工释放
![](/icons/64035dou.gif)
释放只需将接口设为nil即可
---- 接着来实现HTML源码
![](/icons/64035de.gif)
读:
function GetHtml(const WebBrowser:
TWebBrowser):
![](/icons/64035string.gif)
;
const
BufSize = $10000;
var
Size: Int64;
Stream: IStream;
hHTMLText: HGLOBAL;
psi: IPersistStreamInit;
begin
![](/icons/64035if.gif)
not Assigned(WebBrowser.Document) then Exit;
OleCheck(WebBrowser.Document.QueryInterface
(IPersistStreamInit, psi));
try
//OleCheck(psi.GetSizeMax(Size));
hHTMLText := GlobalAlloc(GPTR, BufSize);
![](/icons/64035if.gif)
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), Po
![](/icons/64035int.gif)
er(hHTMLText),
Size);
finally
Stream := nil;
end;
finally
psi := nil;
end;
end;
---- 此
![](/icons/64035hanshu.gif)
有
![](/icons/64035yi.gif)
个参数WebBrowser指定从那个Control控件读取HTML源码
![](/icons/64035dou.gif)
返回
![](/icons/64035yi.gif)
个
![](/icons/64035zifu.gif)
串为此Control控件中
![](/icons/64035de.gif)
HTML源码
![](/icons/64035dou2.gif)
首先还是要先检查WebBrowser.Document对象是否有效
![](/icons/64035dou.gif)
无效则退出;然后取得IPersistStreamInit接口;接着取得HTML源码
![](/icons/64035de.gif)
大小:本来应该使用IPersistStreamInit接口
![](/icons/64035de.gif)
GetSizeMax
![](/icons/64035hanshu.gif)
![](/icons/64035dou.gif)
但在我
![](/icons/64035de.gif)
机器上测试
![](/icons/64035dou.gif)
这个
![](/icons/64035hanshu.gif)
范围值衡为0
![](/icons/64035dou.gif)
无效
![](/icons/64035dou2.gif)
因此只能先定义
![](/icons/64035yi.gif)
个足够大
![](/icons/64035de.gif)
缓冲区
![](/icons/64035dou.gif)
如BufSize = $10000字节(注意此缓冲区应该足够大);然后同样地分配全局堆内存块
![](/icons/64035dou.gif)
建立流
![](/icons/64035dou.gif)
然后将HTML文本写到流中
![](/icons/64035dou2.gif)
![](/icons/64035yinwei.gif)
此HTML文本在流中是以#0结尾
![](/icons/64035de.gif)
![](/icons/64035zifu.gif)
串
![](/icons/64035dou.gif)
因此可以用Size := StrLen(PChar(hHTMLText))取得实际长度
![](/icons/64035dou.gif)
用SetLength(Result, Size);设置返回
![](/icons/64035zifu.gif)
串长度为HTML源码实际长度
![](/icons/64035dou.gif)
最后复制
![](/icons/64035zifu.gif)
串到返回
![](/icons/64035zifu.gif)
串中
---- 至此
![](/icons/64035dou.gif)
直接访问WebBrowserControl控件中
![](/icons/64035de.gif)
HTML源码所需
![](/icons/64035de.gif)
两个
![](/icons/64035hanshu.gif)
全部解析完毕
---- 不过需要注意
![](/icons/64035de.gif)
时
![](/icons/64035dou.gif)
在使用这两个
![](/icons/64035hanshu.gif)
前
![](/icons/64035dou.gif)
最好对WebBrowser.Document对象进行
![](/icons/64035chushi.gif)
化
![](/icons/64035dou2.gif)
下面提供
![](/icons/64035yi.gif)
个
![](/icons/64035hanshu.gif)
![](/icons/64035dou.gif)
通过显示
![](/icons/64035yi.gif)
个空白页面实现WebBrowser.Document对象
![](/icons/64035chushi.gif)
化
procedure ShowBlankPage(WebBrowser:
TWebBrowser);
var
URL: OleVariant;
begin
URL := \'about:blank\';
WebBrowser.Navigate2(URL);
end;
---- 建议在你有WebBrowserControl控件
![](/icons/64035de.gif)
Form
![](/icons/64035de.gif)
FormCreate事件里
![](/icons/64035diaoyong.gif)
此
![](/icons/64035hanshu.gif)
![](/icons/64035dou.gif)
![](/icons/64035chushi.gif)
化WebBrowser.Document对象
---- 本文
![](/icons/64035chengxu.gif)
在Win NT + Delphi 5 环境下调试通过
---- 参考资料:MSDN
---- 特别感谢:白云黄鹤BBS(bbs.whnet.edu.cn)网友AngleFalls
延伸阅读
最新评论