首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi TWebBrowser 獲取 Window 對象的最佳時機:DocumentComplete 事件詳解

     編輯:Delphi

核心問題:何時才能安全獲取 IHTMLWindow2?

許多 Delphi 開發者在 FormCreate 或 Navigate 後立即嘗試訪問 WebBrowser1.Document,卻發現返回 nil 或拋出「介面不支援」異常。根本原因在於:MSHTML DOM 樹尚未構建完成。正確的時機是 DocumentComplete 事件,且必須過濾主框架。

標準實現模式

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OleCtrls, SHDocVw, StdCtrls, MSHTML;

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure WebBrowser1DocumentComplete(ASender: TObject; const pDisp: IDispatch; var URL: OleVariant);
    procedure Button1Click(Sender: TObject);
  private
    FWindow: IHTMLWindow2;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  WebBrowser1.Align := alClient;
  WebBrowser1.Navigate('https://example.com');
end;

// 關鍵:只在主框架完成時獲取 Window
procedure TForm1.WebBrowser1DocumentComplete(ASender: TObject; const pDisp: IDispatch; var URL: OleVariant);
var
  WB: TWebBrowser;
  Doc: IHTMLDocument2;
begin
  WB := ASender as TWebBrowser;
  // pDisp = WB.Application 表示主框架文檔加載完成
  if pDisp = WB.Application then
  begin
    Doc := WB.Document as IHTMLDocument2;
    if Assigned(Doc) then
      FWindow := Doc.parentWindow;  // 緩存供後續使用
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(FWindow) then
  begin
    // 示例:修改頁面內容並彈出 JS 警告
    FWindow.document.body.innerHTML := '

Delphi 動態注入成功

'; FWindow.alert('從 Delphi 呼叫 JavaScript alert()'); end else ShowMessage('Window 尚未就緒,請等待頁面加載完成'); end; end.

關鍵點深度解析

1. 為何要判斷 pDisp = WB.Application?

DocumentComplete 會為每個框架(<iframe>、<frame>)分別觸發。pDisp 參數指向觸發該事件的文檔的 IDispatch 指針。只有主框架的 pDisp 等於 WebBrowser.Application(即 IWebBrowser2 接口)。若不加過濾,iframe 載入時也會覆蓋 FWindow,導致主文檔引用丟失。

2. parentWindow vs Script

  • parentWindow:返回 IHTMLWindow2,標準 DOM Window 對象,支援完整 DOM API。
  • Script:返回 IDispatch,指向腳本引擎的全局對象(JScript/VBScript),適合調用全局 JS 函數或訪問全局變量。二者在現代 IE 引擎中本質相同,但 parentWindow 更符合 DOM 標準。

3. 變量作用域與生命週期

示例中 FWindow 定義為窗體私有字段(private),而非單元級全局變量。優點:

  • 隨窗體銷毀自動釋放 COM 引用(介面變量離開作用域會自動 _Release)。
  • 避免多實例窗體互相干擾。
  • 符合封裝原則,便於單元測試與重構。

4. 異常防護

try
  Doc := WB.Document as IHTMLDocument2;
  if Assigned(Doc) then
    FWindow := Doc.parentWindow;
except
  on E: EOleException do
    // 處理文檔未就緒、跨域拒絕訪問等 COM 錯誤
    LogError('獲取 Window 失敗: ' + E.Message);
end;

進階場景:動態創建的 WebBrowser

若在運行時動態創建 TWebBrowser,需手動連接事件:

procedure TForm1.CreateDynamicBrowser;
var
  WB: TWebBrowser;
begin
  WB := TWebBrowser.Create(Self);
  WB.Parent := Panel1;
  WB.Align := alClient;
  WB.OnDocumentComplete := WebBrowser1DocumentComplete; // 共用事件處理器
  WB.Navigate('https://another-site.com');
end;

常見錯誤對照表

錯誤做法後果正確做法
在 FormCreate 中直接訪問 DocumentDocument 為 nil,AV 異常等待 DocumentComplete
不判斷 pDisp,直接賦值iframe 載入覆蓋主窗口引用if pDisp = WB.Application then
用局部變量接收 Window事件結束變量銷毀,引用失效用字段/屬性持久化引用
忽略跨域訪問異常程式崩潰或靜默失敗try..except 捕獲 EOleException

總結

掌握 DocumentComplete + pDisp 過濾 + 字段緩存 這套「黃金三角」,是 Delphi 控制 TWebBrowser 進行 DOM 操作的基石。在此基礎上,你可以安全地注入腳本、提取數據、模擬用戶交互,構建穩健的網頁自動化應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved