Calling JavaScript in a WebBrowser control from C# 20


Embedding a WebBrowser control in a C# application is very easy to do.  Simply drag and drop one in the Form editor.  So what can you do with it besides writing your own web browser?

I wanted to load my own HTML page and call JavaScript functions within it and for the JavaScript to be able to call functions in C#.  Specifically, I wanted to be able to interact with a public JavaScript API from Google (Google Maps) from the application.

Most of this can be accomplished using a pure JavaScript implementation in a web page, but the user interface is limited as is access to local computer resources, such as files.  With a web server you can process uploaded files, but that requires server resources and a scalable infrastructure if you distribute your application.  It is easier and cheaper to do file processing on the client, which is even more important in a freely distributed application to eliminate extra cost.

I searched around online and it was difficult to find details on how to call JavaScript from a containing C# application.  It turns out to be really easy and worth sharing in case anyone else ever wants to do something similar.

 

Calling JavaScript from C# (See the next section for how to call C# from JavaScript).

So how can you call JavaScript functions in your WebBrowser control?  Call the InvokeScript method on the HtmlDocument.

C#

namespace System.Windows.Forms
{
  public sealed class HtmlDocument
  {
    public object InvokeScript(string scriptName);
    public object InvokeScript(string scriptName, object[] args);
  }
}

For example, let’s assume that you have a System.Windows.Forms.WebBrowser object named webBrowser1 and you want to call a JavaScript function in the HTML page loaded in your WebBrowser called "showMe()"

JavaScript

function showMe()
{
     ... 
}

C#

webBrowser1.Document.InvokeScript("showMe");

Adding parameters gets a bit more complicated, but not much.  You can create an array of parameters as the API suggests and they will be passed in to the JavaScript function.  However, there is an even simpler way to do it.

We will start by calling the following function

JavaScript

function showMe(x,y) 
{
    ...
}

Let’s write a wrapper function in C# using the params keyword to let the compiler do the work for us.  It will automatically convert any extra parameters into an array of objects, just like InvokeScript is expecting.

C#


private object MyInvokeScript(string name, params object[] args)
{
    return webBrowser1.Document.InvokeScript(name, args);
}

int x = 50;
int y = 100;

MyInvokeScript("showMe",x, y);

Note that the InvokeScript will return the value that the JavaScript function returns.  According to the documentation, if it is a native type such as a number or string, it will be returned as a string, but it can also return an object.

JavaScript

function createPoint(x, y)
{
    // Assume I have a Point object
    var p = new Point(x,y);
    return p;
}

function setPoint (p)
{
    // Do something useful with the Point p.
}

C#

object o = MyInvokeScript("createPoint", 50, 100);

It is possible to query information about the object using GetType and InvokeMember but I like that the object can be passed back into JavaScript

C#

MyInvokeScript("setPoint", o);

This is very powerful and, combined with the ability to call from JavaScript into C#, can allow you to embed many web applications that provide a JavaScript API into your C# application.

Calling C# from JavaScript

Simply put, you can expose a C# object to the WebBrowser that the JavaScript can call directly  The WebBrowser class exposes a property called ObjectForScripting that can be set by your application and becomes the window.external object within JavaScript.  The object must have the ComVisibleAttribute set true

C#

[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class ScriptInterface
{
    void callMe()
    {
        … // Do something interesting
    }
}

webBrowser1.ObjectForScripting = new ScriptInterface();

 

JavaScript

window.external.callMe();

 

What next?

With the ability to call JavaScript from C# and C# from JavaScript you can now embed and extend web applications into native applications with ease.  A native application gives you more control over the environment and access to computer resources that you cannot access from a web page.  You can merge, or "mashup", web applications with computer hardware or software in new and interesting ways.

Imagine accessing a GPS connected to your computer and view your current location in an embedded map powered by Google Maps.  What if that included turn by turn directions to your destination?  Why not go even further and convert the directions into speech?  Doing all this on the client saves costs and pushes processing from expensive server hardware to client hardware and opens up interesting mashups to average users who do not have the resources to support their interesting idea for thousands of users.




Leave a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

20 thoughts on “Calling JavaScript in a WebBrowser control from C#

  • trinity

    Thank you very much!!! After taking the time to learn how to work around Silverlight I was heavily disappointed by the fact that it can not be used to access with local files. Atleast I found no information supporting otherwise. My fallback plan was to create a Winform application. This info is the final piece I needed to move ahead.

  • Jens Christian Rasch

    The code you are describing is the same I have found but at the moment I am working with AxWebBrowser instead of the WebBrowser control included in the .NET framework.

    In this AxWebBrowser control I cannot find the equivalent of ObjectForScripting. Do you know how to get this to work?

    Or better, do you have any knowledge on, how to get the WebBrowser control to handle opening of new browser windows and maintain session? :-)

  • josbass

    Great article, concise and to the point! Thanks to your text I managed to include a browser window doing Javascript commands to a web application in my windows application i 5 minutes.

  • Mike

    This is great! I was looking to implement google maps in my application and needed exactly what you have here. One note on your code: In your class “ScriptInterface”, I had to make “CallMe” a public method.

  • Guy Louchen

    Hello, I found this blog post while searching for help with JavaScript. I’ve recently switched browsers from Opera to Internet Explorer 7. Now I seem to have a problem with loading JavaScript. Everytime I go on a page that needs Javascript, my browser doesn’t load and I get a “runtime error javascript.JSException: Unknown name”. I cannot seem to find out how to fix the problem. Any aid is greatly appreciated! Thanks

  • Alon

    Thank you. Your summary is concise and aimed exactly at what I was trying to do. With some minor changes to work with C++, your code got me going within a couple of hours. Nowhere else is this info summarized in one place. Particularly gratifying was seeing fields in my window update live with changes in the Google Earth view.

  • e

    Thanks for this useful write-up. I’m surprised how simple it is to access the hosting application from a script in the browser control; I would hardly have imagined it possible.

  • Anon E. Mous

    Thank you! You have given me exactly what I was looking for to advance a project I am working on. Very well written, easy to follow, perfect guide!

  • tom

    I am also using this technique to call google analytics event tracking from inside a windows application. So i can peform analytics on win forms…

    This blog has bolstered my decision to roll it out and see what happens..
    great stuff!

    Jscript

    function trackEvent(category, action, opt_label, opt_value)
    {
    _gaq.push(['_trackEvent', category, action, opt_label, opt_value]);
    }

    C#

    webBrowser1.Document.InvokeScript(“trackEvent”, args).ToString();

  • Steve

    Very great article ! Thanks a lot.
    Can I ask if this use will be the same to get back the javascript errors ?

    To simplify the request, a major code will be release on a lot of sites and only javascript errors are able to be occur. So, thanks to the web browser, can I list the website and theirs javascript errors ?

    Nice day to you.

    Regards.

    Steve.

  • angel

    Hi..Have you tried use webkit with webkitdotnet or xull runner mozilla with moznet??..I wish give a try them but the documentation is really poor..please if you’ve used some they would be nice see how do this in they…

  • Joao Vale

    I cant pass a list of string from C# to javascript:

    i have in C#:

    MyInvokeScript(“calcHistory”, coordenadas);

    in javascript, i have:

    function calcHistory(z)

    but don’t work :s

    can help me?

  • Roma

    Calling C# from JavaScript

    callMe function doesn’t work. Why doesn’t this function work?

    JS say: …no property or function callMe

  • Ian

    I had been searching for this clearly-explained and straightforward exampkle for hours.
    Thanks for the trouble you took to put this online.
    Ian