procedure TForm1.Button1Click(Sender: TObject); var doc:IHTMLDocument2; begin doc := WebBrowser1.Document as IHTMLDocument2; memo1.text:=doc.body.innerHTML ; NavigateFrameset(doc) ; end;procedure TForm1.NavigateFrameset(document: IHTMLDocument2); var index: Integer; ole_index: OleVariant; frame_dispatch: IDispatch; framed: IHTMLWindow2; begin if document = nil then exit; try Application.MessageBox( PChar('Content:' + String(document.body.innerHTML)), PChar('URL: ' + String(document.URL)),MB_OK or MB_ICONINFORMATION); for index := 1 to document.Frames.Length do try ole_index := index-1; frame_dispatch := document.Frames.Item(ole_index); if frame_dispatch <> nil then begin framed := frame_dispatch as IHTMLWindow2; NavigateFrameset(framed.document); end; except on E: Exception do begin end end; except on E: Exception do begin Application.MessageBox(PChar(E.Message), PChar('Exception')); end; end; end; import the "Microsoft HTML Object Library" (MSHTML.TLB) and include MSHTML_TLB in the unit's uses clause 这个问题困扰我很长时间,今天彻底解决了,希望和大家共享,绝对通过了,别怕麻烦,你拷贝过去,试验一下 可以显示所有frame
to Kimhao(金昊) Create Unit 好像需要很长的时间,导出的文件有11兆多,是不是太久了 to kevin_wang(kevin神) 请把所需要的单元标志出来。
uses MSHTML_TLB 在uses 加上MSTHML_TLB 另外要道入 Microsoft HTML Object Library,安装,这个时间长一点,有时候你以为是 死机了,多等一会
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对象初始化。
var
doc:IHTMLDocument2;
begin
doc := WebBrowser1.Document as IHTMLDocument2;
memo1.text:=doc.body.innerHTML ;
NavigateFrameset(doc) ;
end;procedure TForm1.NavigateFrameset(document: IHTMLDocument2);
var
index: Integer;
ole_index: OleVariant;
frame_dispatch: IDispatch;
framed: IHTMLWindow2;
begin
if document = nil then
exit;
try
Application.MessageBox(
PChar('Content:' + String(document.body.innerHTML)),
PChar('URL: ' + String(document.URL)),MB_OK or
MB_ICONINFORMATION);
for index := 1 to document.Frames.Length do
try
ole_index := index-1;
frame_dispatch := document.Frames.Item(ole_index);
if frame_dispatch <> nil then
begin
framed := frame_dispatch as IHTMLWindow2;
NavigateFrameset(framed.document);
end;
except
on E: Exception do
begin
end
end;
except
on E: Exception do
begin
Application.MessageBox(PChar(E.Message),
PChar('Exception'));
end;
end;
end;
import the "Microsoft HTML Object Library" (MSHTML.TLB) and include MSHTML_TLB in the unit's uses clause
这个问题困扰我很长时间,今天彻底解决了,希望和大家共享,绝对通过了,别怕麻烦,你拷贝过去,试验一下
可以显示所有frame
Create Unit 好像需要很长的时间,导出的文件有11兆多,是不是太久了
to kevin_wang(kevin神)
请把所需要的单元标志出来。
另外要道入 Microsoft HTML Object Library,安装,这个时间长一点,有时候你以为是
死机了,多等一会
通过IHtmlDocument2(webbrowser.Document).Body.OuterText获取string类型的内容。