【问题标题】:TWebBrowser crashes with MOST html filesTWebBrowser 与大多数 html 文件一起崩溃
【发布时间】:2016-09-20 15:02:12
【问题描述】:

我使用 RadPHP 3 中提供的 uHTMLEdit.pas 作为 HTML 编辑器(基于 TWebbrowser)。
当我加载一些 HTML 文件时,程序崩溃了。例如,保存这个 StackOverflow 页面并在 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.

【问题讨论】:

  • 在您调用Doc.Body.SetAttribute 时,AV 可能是 b/c Doc 或 Body 尚未实例化。我对 uHTMLEdit.pas 一无所知。尝试将文件直接加载到 TWebBrowser 中,然后在文档完成事件中将其设置为:Body.SetAttribute...。请记住,默认情况下 TWebBrowser 使用 IE7 兼容模式。见:stackoverflow.com/questions/25843845/…
  • 另外,要切换到编辑模式,您也可以在文档完全加载后尝试Doc.DesignMode := 'On'
  • @kobik-我不认为这是原因。该代码适用于某些文件。所以,Doc 被实例化了。
  • 那么,测试一下。例如if Assigned.... 用于文档和正文。
  • 编辑后,wbBrowser.Navigate(f);异步的。您需要等待 READYSTATE_COMPLETE 的 ReadyState。或使用 DocumentComplete 事件。 IMO,这段代码写得不好。

标签: delphi twebbrowser


【解决方案1】:

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 时,DocDoc.Body 可能尚未准备好/实例化。这就是 AV 的原因。

由于Navigate 是异步的,您需要等待TWebBrowser 完全加载并初始化其DOM。这通常由例如:

  wbBrowser.Navigate(f);
  while wbBrowser.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;
  ...

由于Application.ProcessMessages 被认为是“邪恶的”,并且可能导致重入问题(除非您正确处理它),更好的方法应该是在文档/框架已完全加载的情况下使用TWebBrowser.OnDocumentComplete 事件,并在那里访问(就绪/初始化的)DOM。

【讨论】:

    猜你喜欢
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多