如何在WebBrowser控件中注入Javascript?


81

我已经试过了:

string newScript = textBox1.Text;
HtmlElement head = browserCtrl.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = browserCtrl.Document.CreateElement("script");
lblStatus.Text = scriptEl.GetType().ToString();
scriptEl.SetAttribute("type", "text/javascript");
head.AppendChild(scriptEl);
scriptEl.InnerHtml = "function sayHello() { alert('hello') }";

scriptEl.InnerHtml和scriptEl.InnerText都给出错误:

System.NotSupportedException: Property is not supported on this type of HtmlElement.
   at System.Windows.Forms.HtmlElement.set_InnerHtml(String value)
   at SForceApp.Form1.button1_Click(Object sender, EventArgs e) in d:\jsight\installs\SForceApp\SForceApp\Form1.cs:line 31
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

有没有简单的方法可以将脚本注入dom?

Answers:


101

由于某种原因,Richard的解决方案对我而言不起作用(insertAdjacentText失败,并带有异常)。但是,这似乎可行:

HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
element.text = "function sayHello() { alert('hello') }";
head.AppendChild(scriptEl);
webBrowser1.Document.InvokeScript("sayHello");

该答案说明了如何将IHTMLScriptElement界面引入您的项目。


1
不错,我认为IHTMLScriptElement的用法在任何情况下都使代码意图更加明显。我确实想知道为什么会有例外,但是有时会与COM互操作竞争。
ZeroBugBounce

如何添加对本地js文件的引用?请参阅stackoverflow.com/questions/4029602/...
IAmAN00B

请帮我解决一下这个。你是怎么做到的。我想通过C ++应用程序将JS实时注入到页面中。我应该怎么做。
Johnydep 2011年

这是否也适用于注入jquery文件?
gumuruh

51
HtmlDocument doc = browser.Document;
HtmlElement head = doc.GetElementsByTagName("head")[0];
HtmlElement s = doc.CreateElement("script");
s.SetAttribute("text","function sayHello() { alert('hello'); }");
head.AppendChild(s);
browser.Document.InvokeScript("sayHello");

(在.NET 4 / Windows Forms App中测试)

编辑:修复功能集中的案例问题。


12
我赞赏此解决方案,因为它不依赖(尽管有用!)IHTMLSCriptElement程序集。
米卡·史密斯,

6
@jsight这应该是公认的答案。它与当前答案相同,但是更简单并且没有IHTMLSCriptElement依赖性。
BlueRaja-Danny Pflughoeft

32

这是我从事此工作后发现的最简单的方法:

string javascript = "alert('Hello');";
// or any combination of your JavaScript commands
// (including function calls, variables... etc)

// WebBrowser webBrowser1 is what you are using for your web browser
webBrowser1.Document.InvokeScript("eval", new object[] { javascript });

全局JavaScript函数的eval(str)作用是解析并执行str中编写的内容。在此处检查w3schools参考


22

另外,在.NET 4中,如果使用dynamic关键字,这甚至更加容易:

dynamic document = this.browser.Document;
dynamic head = document.GetElementsByTagName("head")[0];
dynamic scriptEl = document.CreateElement("script");
scriptEl.text = ...;
head.AppendChild(scriptEl);

2
为什么有人为此需要动力?如果您要保存一些类型,由于C#3.0的确存在类型推断,因此var是可以接受的。无需开始调用DLR。
alimbada

23
这基本上就是动态关键字:COM互操作的要点。您实际上在这里没有类型推断,但是有文档。因为例如不能从IHtmlElement分配IHTMLElement2,并且在运行时您仅具有一个COM代理对象。您只需要知道将哪些接口转换为什么即可。dynamic关键字可帮助您减少很多麻烦。您知道该方法存在的原因,为什么要将其强制转换为某个接口?它并不完全“调用DLR”,它只是生成知道如何在COM对象上调用方法的代码(在这种情况下)。
justin.m.chase 2010年

1
@ justin.m。追赶你救了我的命。
Khizar Iqbal

17

如果您真正想要的是运行javascript,这将是最简单的(VB .Net):

MyWebBrowser.Navigate("javascript:function foo(){alert('hello');}foo();")

我想这不会“注入”它,但是它将运行您的功能(如果您要这样做的话)。(以防万一您使问题过于复杂。)并且,如果可以弄清楚如何注入javascript,请将其放入函数“ foo”的主体中,然后让javascript为您注入。


10

HTML文档的托管包装没有完全实现所需的功能,因此您需要使用MSHTML API来完成所需的工作:

1)添加对MSHTML的引用,该引用在COM引用下可能被称为“ Microsoft HTML对象库” 。

2)添加“使用mshtml;” 到您的名称空间。

3)获取对脚本元素的IHTMLElement的引用:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4)调用insertAdjacentText方法,其第一个参数值为“ afterBegin”。列出了所有可能的值此处了

iScriptEl.insertAdjacentText("afterBegin", "function sayHello() { alert('hello') }");

5)现在您将能够在scriptEl.InnerText属性中看到代码。

Hth,理查德


1
很好...这与korchev提供的提示完美配合。我希望我可以为此设置两个公认的解决方案。:)
jsight

8

作为已接受答案的补充,这是IHTMLScriptElement接口的基本定义,不需要包含其他类型库:

[ComImport, ComVisible(true), Guid(@"3050f28b-98b5-11cf-bb82-00aa00bdce0b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(TypeLibTypeFlags.FDispatchable)]
public interface IHTMLScriptElement
{
    [DispId(1006)]
    string text { set; [return: MarshalAs(UnmanagedType.BStr)] get; }
}

因此,WebBrowser控件派生类中的完整代码如下所示:

protected override void OnDocumentCompleted(
    WebBrowserDocumentCompletedEventArgs e)
{
    base.OnDocumentCompleted(e);

    // Disable text selection.
    var doc = Document;
    if (doc != null)
    {
        var heads = doc.GetElementsByTagName(@"head");
        if (heads.Count > 0)
        {
            var scriptEl = doc.CreateElement(@"script");
            if (scriptEl != null)
            {
                var element = (IHTMLScriptElement)scriptEl.DomElement;
                element.text =
                    @"function disableSelection()
                    { 
                        document.body.onselectstart=function(){ return false; }; 
                        document.body.ondragstart=function() { return false; };
                    }";
                heads[0].AppendChild(scriptEl);
                doc.InvokeScript(@"disableSelection");
            }
        }
    }
}

8

我相信从c#向WebBrowser控件HTML文档中注入Javascript的最简单方法是使用要注入的代码作为参数调用“ execScript”方法。

在此示例中,在全局范围内注入并执行了javascript代码:

var jsCode="alert('hello world from injected code');";
WebBrowser.Document.InvokeScript("execScript", new Object[] { jsCode, "JavaScript" });

如果要延迟执行,请注入函数并在以下时间调用它们:

var jsCode="function greet(msg){alert(msg);};";
WebBrowser.Document.InvokeScript("execScript", new Object[] { jsCode, "JavaScript" });
...............
WebBrowser.Document.InvokeScript("greet",new object[] {"hello world"});

这对于Windows窗体和WPF WebBrowser控件有效。

此解决方案不是跨浏览器,因为“ execScript”仅在IE和Chrome中定义。但是问题是关于Microsoft WebBrowser控件的,而IE是唯一受支持的控件。

为了使用有效的跨浏览器方法注入JavaScript代码,请使用新的关键字创建一个Function对象。本示例使用注入的代码创建一个匿名函数并执行它(javascript实现闭包,并且该函数可以访问全局空间而不会造成局部变量污染)。

var jsCode="alert('hello world');";
(new Function(code))();

当然,您可以延迟执行:

var jsCode="alert('hello world');";
var inserted=new Function(code);
.................
inserted();

希望能帮助到你


7

这是使用mshtml的解决方案

IHTMLDocument2 doc = new HTMLDocumentClass();
doc.write(new object[] { File.ReadAllText(filePath) });
doc.close();

IHTMLElement head = (IHTMLElement)((IHTMLElementCollection)doc.all.tags("head")).item(null, 0);
IHTMLScriptElement scriptObject = (IHTMLScriptElement)doc.createElement("script");
scriptObject.type = @"text/javascript";
scriptObject.text = @"function btn1_OnClick(str){
    alert('you clicked' + str);
}";
((HTMLHeadElementClass)head).appendChild((IHTMLDOMNode)scriptObject);

2
由于这是社区资源,因此他的回答对其他人(例如我自己)仍然有用。+1相当于mshtml,为我省了一个问题。
Kyeotic 2011年

1
对于发现此问题的任何人,请从最后一行删除“ class”,((HTMLHeadElement)head).appendChild((IHTMLDOMNode)scriptObject);否则应阅读该书,否则会出错。
Kyeotic 2011年

1
无论如何,管理员可以提升这个答案?实际上,以上所有这些都是错误的。这是后来者,但实际上是最正确的答案。
justin.m.chase 2012年

2

我用这个:D

HtmlElement script = this.WebNavegador.Document.CreateElement("SCRIPT");
script.SetAttribute("TEXT", "function GetNameFromBrowser() {" + 
"return 'My name is David';" + 
"}");

this.WebNavegador.Document.Body.AppendChild(script);

然后,您可以执行以下命令并获得结果:

string myNameIs = (string)this.WebNavegador.Document.InvokeScript("GetNameFromBrowser");

希望对您有所帮助


2

如果您试图从WebBrowser控件中加载的页面中检索变量的值,则这是一个VB.Net示例。

步骤1)在您的项目中将COM引用添加到Microsoft HTML对象库

步骤2)接下来,将此VB.Net代码添加到您的Form1中以导入mshtml库:
导入mshtml

步骤3)在您的“公共类Form1”行上方添加以下VB.Net代码:
<System.Runtime.InteropServices.ComVisibleAttribute(True)>

步骤4)将WebBrowser控件添加到您的项目

步骤5)将此VB.Net代码添加到您的Form1_Load函数:
WebBrowser1.ObjectForScripting = Me

第6步)添加此VB.Net子项,该子项会将功能“ CallbackGetVar”注入到网页的Javascript中:

Public Sub InjectCallbackGetVar(ByRef wb As WebBrowser)
    Dim head As HtmlElement
    Dim script As HtmlElement
    Dim domElement As IHTMLScriptElement

    head = wb.Document.GetElementsByTagName("head")(0)
    script = wb.Document.CreateElement("script")
    domElement = script.DomElement
    domElement.type = "text/javascript"
    domElement.text = "function CallbackGetVar(myVar) { window.external.Callback_GetVar(eval(myVar)); }"
    head.AppendChild(script)
End Sub

步骤7)添加以下VB.Net子项,然后在被调用时查找Javascript:

Public Sub Callback_GetVar(ByVal vVar As String)
    Debug.Print(vVar)
End Sub

步骤8)最后,要调用Javascript回调,请在按下按钮或喜欢的地方添加此VB.Net代码:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    WebBrowser1.Document.InvokeScript("CallbackGetVar", New Object() {"NameOfVarToRetrieve"})
End Sub

第9步)如果使您惊奇的是它起作用了,那么您可能想读一下第6步中使用的Javascript“ eval”函数,这才使这成为可能。它将使用一个字符串并确定该名称是否存在变量,如果存在,则返回该变量的值。


1

您始终可以使用“ DocumentStream”或“ DocumentText”属性。对于使用HTML文档,我建议使用HTML Agility Pack


不错的提示...我敢肯定,lib在某些时候会派上用场。
jsight

1

我用这个:

webBrowser.Document.InvokeScript("execScript", new object[] { "alert(123)", "JavaScript" })

0

您要做的是使用Page.RegisterStartupScript(key,script):

有关更多详细信息,请参见此处:http : //msdn.microsoft.com/zh-cn/library/aa478975.aspx

基本上,您要做的是构建您的javascript字符串,将其传递给该方法并为其赋予唯一的ID(以防您尝试在页面上将其注册两次。)

编辑:这就是你所说的触发快乐。随意降低它。:)


4
ASP.Net与在Winforms应用程序中编写WebBrowser控件的脚本无关。
jsight

我可能会以相同的方式阅读不足并给出相同的错误答案
Grank

0

如果需要注入整个文件,则可以使用以下命令:

With Browser.Document
   Dim Head As HtmlElement = .GetElementsByTagName("head")(0)
   Dim Script As HtmlElement = .CreateElement("script")
   Dim Streamer As New StreamReader(<Here goes path to file as String>)
   Using Streamer
       Script.SetAttribute("text", Streamer.ReadToEnd())
   End Using
   Head.AppendChild(Script)
   .InvokeScript(<Here goes a method name as String and without parentheses>)
End With

记住要导入System.IO才能使用StreamReader。我希望这有帮助。


我知道一年前3天就回答了这个问题,但是您可以使用它来将文件放入input type="file"分区吗?
克里斯·霍布斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.