TWebBrowser 因最多 html 个文件而崩溃
TWebBrowser crashes with MOST html files
我正在使用 RadPHP 3 中提供的 uHTMLEdit.pas 作为 HTML 编辑器(基于 TWebbrowser)。
当我加载一些 HTML 文件时,程序崩溃了。例如,保存此 Whosebug 页面并将其加载到 TWebbrowser 中。它会崩溃:
崩溃详情:
Access violation at address 005FAF9B in module 'TestHtmlEditRad.exe'. Read of address 00000000.
线上崩溃Doc.Body.SetAttribute('contentEditable', 'true', 0)
:
procedure THTMLEdit.EditText(const text: string);
VAR
Doc: IHTMLDocument2;
sl: TStringList;
f: string;
begin
sl := TStringList.Create;
TRY
sl.Text := text;
f := gettempfile('.html');
sl.SaveToFile(f);
wbBrowser.Navigate(f);
Doc := GetDocument;
if Doc <> NIL
then Doc.Body.SetAttribute('contentEditable', 'true', 0); **Crash HERE**
DeleteFile(f);
FINALLY
FreeAndNil(sl);
END;
end;
它适用于小型(不那么复杂)HTML 文件。
我的问题是:TWebBrowser崩溃正常吗?
要重现您只需要此代码和 uHTMLEdit.pas(已随 Embarcadero RadPHP 一起提供)。
unit FormMain;
interface
USES
Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, uHTMLEdit;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
IMPLEMENTATION {$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
VAR debug: string;
begin
debug:= stringfromfile('test.htm'); // this temporary line of code is mine, for testing. All other code is Embarcadero's
with THTMLEditDlg.Create(application) do begin
try
edittext(debug);
if ShowModal= 0
then debug:= getText;
finally
free;
end;
end;
end;
end.
在THTMLEdit.EditText
方法中:
...
wbBrowser.Navigate(f);
Doc := GetDocument;
if Doc <> NIL
then Doc.Body.SetAttribute('contentEditable', 'true', 0); **Crash HERE**
...
wbBrowser.Navigate(f)
是 异步的 。当您调用 Doc.Body.SetAttribute
时,Doc
或 Doc.Body
可能 还不是 ready/instantiated。这就是AV的原因。
由于 Navigate
是异步的,您需要等待 TWebBrowser
完全加载并初始化它的 DOM。这通常由例如:
wbBrowser.Navigate(f);
while wbBrowser.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
...
由于 Application.ProcessMessages
被认为是 "evil",并且可能导致重新进入问题(除非您正确处理),更好的方法应该是使用 TWebBrowser.OnDocumentComplete
事件,其中document/frame 已完全加载,并在那里访问 (ready/initialized) DOM。
我正在使用 RadPHP 3 中提供的 uHTMLEdit.pas 作为 HTML 编辑器(基于 TWebbrowser)。
当我加载一些 HTML 文件时,程序崩溃了。例如,保存此 Whosebug 页面并将其加载到 TWebbrowser 中。它会崩溃:
崩溃详情:
Access violation at address 005FAF9B in module 'TestHtmlEditRad.exe'. Read of address 00000000.
线上崩溃Doc.Body.SetAttribute('contentEditable', 'true', 0)
:
procedure THTMLEdit.EditText(const text: string);
VAR
Doc: IHTMLDocument2;
sl: TStringList;
f: string;
begin
sl := TStringList.Create;
TRY
sl.Text := text;
f := gettempfile('.html');
sl.SaveToFile(f);
wbBrowser.Navigate(f);
Doc := GetDocument;
if Doc <> NIL
then Doc.Body.SetAttribute('contentEditable', 'true', 0); **Crash HERE**
DeleteFile(f);
FINALLY
FreeAndNil(sl);
END;
end;
它适用于小型(不那么复杂)HTML 文件。
我的问题是:TWebBrowser崩溃正常吗?
要重现您只需要此代码和 uHTMLEdit.pas(已随 Embarcadero RadPHP 一起提供)。
unit FormMain;
interface
USES
Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, uHTMLEdit;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
IMPLEMENTATION {$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
VAR debug: string;
begin
debug:= stringfromfile('test.htm'); // this temporary line of code is mine, for testing. All other code is Embarcadero's
with THTMLEditDlg.Create(application) do begin
try
edittext(debug);
if ShowModal= 0
then debug:= getText;
finally
free;
end;
end;
end;
end.
在THTMLEdit.EditText
方法中:
...
wbBrowser.Navigate(f);
Doc := GetDocument;
if Doc <> NIL
then Doc.Body.SetAttribute('contentEditable', 'true', 0); **Crash HERE**
...
wbBrowser.Navigate(f)
是 异步的 。当您调用 Doc.Body.SetAttribute
时,Doc
或 Doc.Body
可能 还不是 ready/instantiated。这就是AV的原因。
由于 Navigate
是异步的,您需要等待 TWebBrowser
完全加载并初始化它的 DOM。这通常由例如:
wbBrowser.Navigate(f);
while wbBrowser.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
...
由于 Application.ProcessMessages
被认为是 "evil",并且可能导致重新进入问题(除非您正确处理),更好的方法应该是使用 TWebBrowser.OnDocumentComplete
事件,其中document/frame 已完全加载,并在那里访问 (ready/initialized) DOM。