Delphi 或 C# 实现 WebBrowser 进行 JS 注入

| 选择喜欢的代码风格  

Delphi WebBrowser JS 注入需要用到 OleVariant:


WebBrowser 注入 JS 具体 Delphi 代码如下:

procedure TfrmMain.LoatExternalJS;
var
  i:integer;
  o:OleVariant;

begin
  o := WebBrowser1.OleObject.document.createElement('script');
  o.type := 'text/javascript';
  o.text := 'alert("Hello, JS 注入成功!");'; // 注意这里

  WebBrowser1.OleObject.document.getElementsByTagName('head').item(0).appendChild(o);

end;

procedure TfrmMain.WebBrowser1DocumentComplete(ASender: TObject;
  const pDisp: IDispatch; const URL: OleVariant);
begin

  if WebBrowser1.LocationURL = URL then begin
    LoatExternalJS(); // 在页面加载完成的时候,调用 JS 注入
  end;

  Memo1.Lines.Add(WebBrowser1.LocationURL);
end;

WebBrowser 注入 JS 具体 Delphi 最终效果如下:


Delphi WebBrowser JS 注入

刚才的 WebBrowser 注入 JS 是直接 text 代码片段,如果希望直接引入的是 JS 文件,则具体 Delphi 代码改成 o.src 即可:

procedure TfrmMain.LoatExternalJS;
var
  i:integer;
  o:OleVariant;

begin
  o := WebBrowser1.OleObject.document.createElement('script');
  o.type := 'text/javascript';  
  o.src := 'https://commandnotfound.cn/plugin.js'; // 注意这里 JS 的 src

  WebBrowser1.OleObject.document.getElementsByTagName('head').item(0).appendChild(o);

end;

...

其他 StackOverflow 上的一个完整例子,需要用到 IHtmlScriptElement

unit u_frm_SO27091639;

interface

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

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure LoadDocFromString(Webbrowser : TWebbrowser);

var
  Strm    : TStringStream;
  Adapter : TStreamAdapter;

begin
 WebBrowser.Navigate('about:blank');
 // warning - don't use this trick in production code, use the `OnDocumentComplete` event
 while WebBrowser.ReadyState <> READYSTATE_INTERACTIVE do
  Application.ProcessMessages;
 // end of warning
 Strm := TStringStream.Create;
 try
  Strm.WriteString('<html><body>Something<br></body></html>');
  Strm.Seek(0, 0);
  Adapter := TStreamAdapter.Create(Strm);
  (WebBrowser.Document as IPersistStreamInit).Load(Adapter) ;
 finally
  Strm.Free;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);

var
  Doc2     : IHtmlDocument2;
  Script   : IHtmlDOMNode;
  HTMLWindow: IHTMLWindow2;

begin
 Doc2 := Webbrowser1.Document as IHtmlDocument2;
 if Assigned(Doc2.body) then
  begin
   Script := Doc2.createElement('script') as IHTMLDOMNode;
   (Script as IHTMLScriptElement).text := 'function helloWorld() { alert("hello world!") }';
   (Doc2.body as IHtmlDomNode).appendChild(Script);
   HTMLWindow := Doc2.parentWindow;
   if Assigned(HTMLWindow) then
    HTMLWindow.execScript('helloWorld()', 'JavaScript')
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 LoadDocFromString(Webbrowser1);
end;

end.

C# WebBrowser JS 注入思路同理,也是在 DocumentComplete 的时候:


exjsUrl = "https://commandnotfound.cn/plugin.js";

private void LoadExternalJs()
{
    var head = this.browser.Document.GetElementsByTagName("head");
    if (head == null || browser.Document.GetElementById("ex_js") != null)
        return;

    var script = browser.Document.CreateElement("script");
    script.SetAttribute("type", "text/javascript");
    script.SetAttribute("id", "ex_js");
    script.SetAttribute("src", exjsUrl);
    head[0].AppendChild(script);
}

private void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url == browser.Url)
    {
        LoadExternalJs();
        ...
    }
}

C# WebBrowser JS 注入还有其他几种方式:


C# 追加 script 元素,这个方式,可以传参及取得返回值。

var script = browser.Document.CreateElement("script");

script.SetAttribute("type", "text/javascript");
script.SetAttribute("text", "function _func() {" + string.Format(jsCode, "method 1") + "}");

browser.Document.Body.AppendChild(script);
browser.Document.InvokeScript("_func");
}

C# DomDocument ,这种方式,必须在程序中引用 MSHTML 对象(不能传参,且没有返回值):

var doc = this.browser.Document.DomDocument as IHTMLDocument2;
var win = doc.parentWindow as IHTMLWindow2;

jsCode = string.Format(jsCode, "method 2"); 
win.execScript(jsCode, "javascript");

C# 还有一个简单方式,直接调用:

browser.Document.InvokeScript("execScript", new Object[] { string.Format(jsCode, "method 3"), "javascript" });

Delphi WebBrowser JS 注入扩展阅读:




发表评论