如何在WebBrowser控件中注入Javascript?
我试过这个:
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?
出于某种原因理查德的解决scheme没有在我的工作(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
接口进入你的项目。
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中testing)
编辑:修正function集中的大小写问题。
另外,在.NET 4中,如果使用dynamic关键字,则更容易:
dynamic document = this.browser.Document; dynamic head = document.GetElementsByTagName("head")[0]; dynamic scriptEl = document.CreateElement("script"); scriptEl.text = ...; head.AppendChild(scriptEl);
这是我在工作之后find的最简单的方法:
string jCode = "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[] { jCode });
eval(str)
所做的全局JavaScript函数是parsing并执行str中写入的内容。 在这里检查w3schools 。
如果你真正想要的是运行JavaScript,这将是最简单的(VB .Net):
MyWebBrowser.Navigate("javascript:function foo(){alert('hello');}foo();")
我想这不会“注入”它,但它会运行你的function,如果这就是你以后。 (以防万一你把这个问题搞得太复杂了。)如果你能弄清楚如何注入javascript,把它放到函数“foo”的主体中,让javascript为你做注入。
HTML文档的托pipe包装并没有完全实现你需要的function,所以你需要深入到MSHTML API来完成你想要的东西:
1)添加一个对MSHTML的引用,它将在COM引用下被称为“Microsoft HTML Object Library”。
2)添加“使用mshtml;” 到你的名字空间。
3)获取脚本元素的IHTMLElement的引用:
IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;
4)调用insertAdjacentText方法,第一个参数值为“afterBegin”。 所有可能的值在这里列出:
iScriptEl.insertAdjacentText("afterBegin", "function sayHello() { alert('hello') }");
5)现在你将能够看到scriptEl.InnerText属性中的代码。
理查德
这是一个使用mshtml的解决scheme
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);
我相信最简单的方法来从C#注入WebBrowser控制HTML文档中的Javascript是调用“execStrip”方法的代码被注入作为参数。
在这个例子中,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控件有效。
这个解决scheme不是跨浏览器,因为“execScript”只在IE和Chrome中定义。 但问题是关于微软WebBrowser控件和IE是唯一支持的。
要获得有效的跨浏览器方法来注入JavaScript代码,请使用新的关键字创build一个Function对象。 这个例子通过注入代码创build一个匿名函数并执行它(javascript实现了闭包,函数可以访问全局空间而没有局部variables污染)。
var jsCode="alert('hello world');"; (new Function(code))();
当然,你可以延迟执行:
var jsCode="alert('hello world');"; var inserted=new Function(code); ................. inserted();
希望它有帮助
作为接受的答案的后续,这是IHTMLScriptElement
接口的最小定义,不需要包含其他types的库:
[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"); } } } }
我用这个: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");
我希望能有所帮助
您始终可以使用“DocumentStream”或“DocumentText”属性。 为了处理HTML文档,我推荐使用HTML Agility Pack 。
这里是一个VB.Net的例子,如果您试图检索WebBrowser控件中加载页面内的variables的值。
步骤1)将您的项目中的COM引用添加到Microsoft HTML对象库
步骤2)接下来,将此VB.Net代码添加到您的Form1以导入mshtml库:
导入mshtml
步骤3)在“公共类Form1”行上添加此VB.Net代码:
<System.Runtime.InteropServices.ComVisibleAttribute(真)>
步骤4)将WebBrowser控件添加到您的项目
步骤5)将此VB.Net代码添加到您的Form1_Load函数:
WebBrowser1.ObjectForScripting =我
第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步)最后,要调用Javascriptcallback,请在按下button时添加此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”函数,这是可能的。 它将接收一个string,并确定一个variables是否以该名称存在,如果是,则返回该variables的值。
你想要做的是使用Page.RegisterStartupScript(key,script):
详情请参阅: http : //msdn.microsoft.com/en-us/library/aa478975.aspx
你基本上做的是build立你的JavaScriptstring,传递给该方法,并给它一个唯一的ID(如果你尝试在一个页面上注册两次)。
编辑:这就是你所说的触发快乐。 随意下来吧。 🙂
如果你需要注入一个完整的文件,那么你可以使用这个:
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。 我希望这对你有所帮助