在Delphi应用程序中使用TGeckoBrowser时如何避免异常

时间:2014-08-30 11:24:57

标签: delphi gecko geckosdk

昨天在这里提示q,我正在尝试重新熟悉TGeckoBrowser 从这里:http://sourceforge.net/p/d-gecko/wiki/Home

(Nb:需要安装Mozilla XulRunner软件包)

自从我上次尝试在WinXP时代以来,事情似乎已经向后移动了一点 使用最小的D7项目导航到URL,我收到了我不记得的错误 以前见过。我在下面提供了我的代码。这些是我遇到的错误 导航到www.google.com,news.bbc.co.uk等网站,当然还有这里。

  1. 第一个例外 - “Safecall方法中的异常” - 在我的表单首次显示之前发生,然后在导航到任何地方之前。我以TApplication.OnException处理程序的形式解决了这个问题。
  2. 我的q是:a)有没有人知道如何首先避免它或b)有没有比设置TApplication.Exception处理程序更整洁的方法来捕获它,这对我来说总是让我觉得有点像 承认失败(我的意思是让一个人避免用户看到异常,根本没有应用程序范围的处理程序)。

    此代码中出现此异常:

    procedure TCustomGeckoBrowser.Paint;
    var
      rc: TRect;
      baseWin: nsIBaseWindow;
    begin
      if csDesigning in ComponentState then
      begin
        rc := ClientRect;
        Canvas.FillRect(rc);
      end else
      begin
        baseWin := FWebBrowser as nsIBaseWindow;
        baseWin.Repaint(True);
      end;
      inherited;
    end;
    

    在对baseWin.Repaint的调用中,所以大概是这样的 大概来自界面的另一面。我只是第一次得到它 时间.Paint被称为。我注意到那时,baseWin为GetVisibility返回False, 因此我的TForm1.Loaded中的实验代码,看看是否会避免它。 它没有。

    2.a调用GeckoBrowser1.LoadURI后,我得到“无效的浮点运算” 一次或多次,具体取决于所加载的URL。

    2.b同样,根据URL,我得到:“模块js3250.dll中地址为556318B3的访问冲突。读取地址00000008.”或类似的。在某些页面上,它每隔几秒发生一次(感谢我想象一下页面中的一些JS计时器代码)。

    2a&在下面的TForm1.OnCreate中调用Set8087CW可以避免使用2b,但我是 提到他们主要是因为有人认出他们和一起作为对症 某种系统性问题,但谷歌也会发现这个问题 对于遇到这些症状的其他人。

    回到我的q 1b),“StcWndProc->中发生了”Safecall方法中的异常“。 TWinControl.MainWndProc-> [...] - > TCustomGeckoBrowser.Paint。而不是使用 TApplication.OnException处理程序,有没有办法进一步捕获异常 调用链,以避免修改TCustomGeckoBrowser.Paint的代码 把处理程序放在那里?

    更新:评论引起了我对与SafeCall相关的文档的注意:

    如果尚未设置safecall错误处理程序并且safecall例程返回非0 HResult,或者safecall错误处理程序未引发异常,则会引发ESafecallException。如果发生此异常,Comobj单元可能从应用程序的使用列表(Delphi)中丢失或未包含在项目源文件(C ++)中。您可能需要考虑从引起异常的例程中删除safecall调用约定。

    GeckoBrowser源附带一个单元BrowserSupports,它看起来像一个类型库导入单元,除了它似乎已经手动准备。它包含一个接口,其中包含产生SafeCall异常的Repaint方法。

      nsIBaseWindow = interface(nsISupports)
      ['{046bc8a0-8015-11d3-af70-00a024ffc08c}']
        procedure InitWindow(parentNativeWindow: nativeWindow; parentWidget: nsIWidget; x: PRInt32; y: PRInt32; cx: PRInt32; cy: PRInt32); safecall;
        procedure Create(); safecall;
        procedure Destroy(); safecall;
      [...]
        procedure Repaint(force: PRBool); safecall;
      [...]
      end;
    

    根据quoyed文档中的建议,我在Repaint成员(但只有那个成员)上将“safecall”更改为StdCall,并且,presto!,异常停止发生。如果它在接下来的几天内没有重新出现,我会将其作为答案发布,除非有人想出更好的答案。

    我的项目代码:

    uses
      BrowserSupports;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Set8087CW($133F);
      Application.OnException := HandleException;
    end;
    
    procedure TForm1.HandleException(Sender: TObject; E: Exception);
    begin
      Inc(Errors);
      Caption := Format('Errors %d, msg: %s', [Errors, E.Message]);
      Screen.Cursor := crDefault;
    end;
    
    type
      TMyGeckoBrowser = class(TGeckoBrowser);
    
    procedure TForm1.Loaded;
    begin
      inherited;
      GeckoBrowser1.HandleNeeded;
     (TMyGeckoBrowser(GeckoBrowser1).WebBrowser as nsIBaseWindow).SetVisibility(True);
    end;
    
    procedure TForm1.btnLoadUrlClick(Sender: TObject);
    begin
      try
        GeckoBrowser1.LoadURI(edUrl.Text);
      except
      end;
    end;
    

1 个答案:

答案 0 :(得分:0)

查看标题,Repaint的原型实际如下:

HRESULT __stdcall Repaint(PRBool force);

这意味着

procedure Repaint(force: PRBool); safecall;

是一个合理的声明。请记住,safecall执行参数重写以将COM错误代码转换为异常。

这意味着如果对Repaint的调用返回指示失败的值,那么safecall机制将表示为异常。如果你想忽略这个特殊的异常,那么在源代码中这样做会更清晰:

try
  baseWin.Repaint(True);
except
  on EOleException do
    ; // ignore
end;

如果您希望避免处理异常,那么您可以切换到stdcall,但您必须记住撤消参数重写。

function Repaint(force: PRBool): HRESULT; stdcall;

现在你可以这样写:

if Failed(baseWin.Repaint(True)) then
  ; // handle the error if you really wish to, or just ignore it

请注意,Failed单位定义了ActiveX

如果您想进一步排除错误,可以查看错误代码:

var
  hres: HRESULT;
....
hres := baseWin.Repaint(True);
// examine hres

或者,如果您要将该函数保留为s​​afecall,则可以从EOleException实例的ErrorCode属性中检索错误代码。