[c#] How to inject Javascript in WebBrowser control?

I've tried this:

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 and scriptEl.InnerText both give errors:

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)

Is there an easy way to inject a script into the dom?

This question is related to c# javascript .net winforms webbrowser-control

The answer is


The managed wrapper for the HTML document doesn't completely implement the functionality you need, so you need to dip into the MSHTML API to accomplish what you want:

1) Add a reference to MSHTML, which will probalby be called "Microsoft HTML Object Library" under COM references.

2) Add 'using mshtml;' to your namespaces.

3) Get a reference to your script element's IHTMLElement:

IHTMLElement iScriptEl = (IHTMLElement)scriptEl.DomElement;

4) Call the insertAdjacentText method, with the first parameter value of "afterBegin". All the possible values are listed here:

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

5) Now you'll be able to see the code in the scriptEl.InnerText property.

Hth, Richard


You can always use a "DocumentStream" or "DocumentText" property. For working with HTML documents I recommend a HTML Agility Pack.


As a follow-up to the accepted answer, this is a minimal definition of the IHTMLScriptElement interface which does not require to include additional type libraries:

[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; }
}

So a full code inside a WebBrowser control derived class would look like:

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");
            }
        }
    }
}

What you want to do is use Page.RegisterStartupScript(key, script) :

See here for more details: http://msdn.microsoft.com/en-us/library/aa478975.aspx

What you basically do is build your javascript string, pass it to that method and give it a unique id( in case you try to register it twice on a page.)

EDIT: This is what you call trigger happy. Feel free to down it. :)


this is a solution using 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);

Here is a VB.Net example if you are trying to retrieve the value of a variable from within a page loaded in a WebBrowser control.

Step 1) Add a COM reference in your project to Microsoft HTML Object Library

Step 2) Next, add this VB.Net code to your Form1 to import the mshtml library:
Imports mshtml

Step 3) Add this VB.Net code above your "Public Class Form1" line:
<System.Runtime.InteropServices.ComVisibleAttribute(True)>

Step 4) Add a WebBrowser control to your project

Step 5) Add this VB.Net code to your Form1_Load function:
WebBrowser1.ObjectForScripting = Me

Step 6) Add this VB.Net sub which will inject a function "CallbackGetVar" into the web page's 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

Step 7) Add the following VB.Net sub which the Javascript will then look for when invoked:

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

Step 8) Finally, to invoke the Javascript callback, add this VB.Net code when a button is pressed, or wherever you like:

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

Step 9) If it surprises you that this works, you may want to read up on the Javascript "eval" function, used in Step 6, which is what makes this possible. It will take a string and determine whether a variable exists with that name and, if so, returns the value of that variable.


If you need to inject a whole file then you can use this:

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

Remember to import System.IO in order to use the StreamReader. I hope this helps.


I used this :D

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

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

Then you can execute and get the result with:

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

I hope to be helpful


i use this:

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

I believe the most simple method to inject Javascript in a WebBrowser Control HTML Document from c# is to invoke the "execScript" method with the code to be injected as argument.

In this example the javascript code is injected and executed at global scope:

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

If you want to delay execution, inject functions and call them after:

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

This is valid for Windows Forms and WPF WebBrowser controls.

This solution is not cross browser because "execScript" is defined only in IE and Chrome. But the question is about Microsoft WebBrowser controls and IE is the only one supported.

For a valid cross browser method to inject javascript code, create a Function object with the new Keyword. This example creates an anonymous function with injected code and executes it (javascript implements closures and the function has access to global space without local variable pollution).

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

Of course, you can delay execution:

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

Hope it helps


Also, in .NET 4 this is even easier if you use the dynamic keyword:

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

Here is the easiest way that I found after working on this:

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 });

What global JavaScript function eval(str) does is parses and executes whatever is written in str. Check w3schools ref here.


If all you really want is to run javascript, this would be easiest (VB .Net):

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

I guess that this wouldn't "inject" it but it'll run your function, if that's what you're after. (Just in case you've over-complicated the problem.) And if you can figure out how to inject in javascript, put that into the body of the function "foo" and let the javascript do the injection for you.


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");

(tested in .NET 4 / Windows Forms App)

Edit: Fixed case issue in function set.


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to .net

You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to use Bootstrap 4 in ASP.NET Core No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Update .NET web service to use TLS 1.2 EF Core add-migration Build Failed What is the difference between .NET Core and .NET Standard Class Library project types? Visual Studio 2017 - Could not load file or assembly 'System.Runtime, Version=4.1.0.0' or one of its dependencies Nuget connection attempt failed "Unable to load the service index for source" Token based authentication in Web API without any user interface

Examples related to winforms

How to set combobox default value? Get the cell value of a GridView row Getting the first and last day of a month, using a given DateTime object Check if a record exists in the database Delete a row in DataGridView Control in VB.NET How to make picturebox transparent? Set default format of datetimepicker as dd-MM-yyyy Changing datagridview cell color based on condition C# Inserting Data from a form into an access Database How to use ConfigurationManager

Examples related to webbrowser-control

Options for embedding Chromium instead of IE WebBrowser control with WPF/C# Use latest version of Internet Explorer in the webbrowser control Difference between F5, Ctrl + F5 and click on refresh button? Load local HTML file in a C# WebBrowser Will the IE9 WebBrowser Control Support all of IE9's features, including SVG? How can I hide the Adobe Reader toolbar when displaying a PDF in the .NET WebBrowser control? How to wait until WebBrowser is completely loaded in VB.NET? Detect WebBrowser complete page loading Disable JavaScript error in WebBrowser control Replacing .NET WebBrowser control with a better browser, like Chrome?