Click here to Skip to main content
Email Password   helpLost your password?

Contents

Introduction

This article is about passing data between VB.NET/C# WinForms and JavaScript.

Before reading further, let me warn you that this article is not about ASP.NET. Concepts covered in the article are applied to Desktop applications.

Background

I was working on a project which required data transfer between my VB.NET WinForms application and the JavaScript (inside an HTML page). Along the way, I hit certain problems, and trying to resolve them cost plenty of time on the web (on Google mostly), so I thought of this article as a platform for developers looking to sort out similar issues. There isn't much detail on this topic on the web apart from a couple of Hello World examples from Microsoft on MSDN.

Starting point

OK, without any further talk, I will dig in to the subject.

Hello World

To start off, we'll start with a very simple example; all this will do is call a JavaScript function from VB.NET to display an alert with message 'Hello world'. Similarly, from the HTML page using JavaScript, we'll call a VB.NET function which will again display a messagebox with the message 'Hello world'. These are the steps you need to do to make it happen:

Calling JavaScript from VB.NET

Calling VB.NET from JavaScript

Passing arguments to functions

Passing arguments to JavaScript functions

To pass arguments to a JavaScript function, you need to simply declare functions in your JavaScript code like you normally do. In your VB.NET code, you can pass a single argument like:

Me.WebBrowser1.Document.InvokeScript("javascriptFunction", _
   New String() {"Message from vb.net to javascript"})

If you want to pass more than one variable, you can simply add it like:

Me.WebBrowser1.Document.InvokeScript("javascriptFunction", _
   New String() {"Message from vb.net to javascript", _
  "Argument 1","Argument 2" , "Argument n"})

So far, I am only passing string type arguments, but you are not restricted to simple strings. You can easily pass string, integers, booleans without any special additions. E.g.:

Me.WebBrowser1.Document.InvokeScript("javascriptFunction", _
   New Object() {"Message from vb.net to javascript",200,true})

Arguments are not restricted to simple types, you can pass any type you want. The only restriction is you'll have to make it COM visible. In this example, I am going to pass a Person object to JavaScript. To make it work, I'll follow these steps:

Passing arrays to JavaScript functions (unsuccessful attempt)

OK, passing arrays to JavaScript. Some developers might think why is it a separate section. The reason is it is not straightforward to pass arrays as most people would think. If you try this code:

Dim firstNames() As String = {"John", "Richard", "Micheal"}
Dim lastNames() As String = {"Smith", "Stone", "Day"}
Me.WebBrowser1.Document.InvokeScript("passNameArrays", _
                        New Object() {firstNames, lastNames})

In your JavaScript, if you try doing this:

<script type="text/javascript">
    function passNameArrays(firstNames, lastNames) {
        alert(firstNames[0]);
    }
</script>

you'll get a JavaScript error (if error messages are enabled).

So, why didn't that work, you must be asking. The reason is pretty simple. You can only pass simple types, and arrays are not simple types. You'll have to put a workaround to pass arrays.

Passing arrays to JavaScript functions (successful attempt)

OK, it is understood that we can't pass arrays to JavaScript (at least, I am not aware of a way for passing them; if anyone knows a method, they are welcome to correct me). The simplest workaround is to create a type which wraps your array and passes that type instead of a simple array. E.g., you could wrap your array of strings like:

<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
Public Class myArr
    Implements IList(Of String)

    Private _list As New List(Of String)

    Public Sub New()

    End Sub
    Public Sub New(ByVal arr() As String)
        For Each Str As String In arr
            Me._list.Add(Str)
        Next
    End Sub

    Public Sub Add(ByVal item As String) _
           Implements System.Collections.Generic.ICollection(Of String).Add
        Me._list.Add(item)
    End Sub

    Public Sub Clear() _
           Implements System.Collections.Generic.ICollection(Of String).Clear
        Me._list.Clear()
    End Sub

    Public Function Contains(ByVal item As String) As Boolean _
           Implements System.Collections.Generic.ICollection(Of String).Contains
        Return _list.Contains(item)
    End Function

    Public Sub CopyTo(ByVal array() As String, ByVal arrayIndex As Integer) _
           Implements System.Collections.Generic.ICollection(Of String).CopyTo

    End Sub

    Public ReadOnly Property Count() As Integer _
           Implements System.Collections.Generic.ICollection(Of String).Count
        Get
            Return Me._list.Count
        End Get
    End Property

       'Rest of the class method needs to be implemented here
End Class

And now, if we take on the example from the previous section where we unsuccessfully tried to pass an array of first and last names, let's give it another try:

Dim firstNames As New myArr(New String() {"John", "Richard", "Micheal"})
Dim lastNames As New myArr(New String() {"Smith", "Stone", "Day"})
Me.WebBrowser1.Document.InvokeScript("passNameArrays", _
               New Object() {firstNames, lastNames})

In your JavaScript, you could use it like:

<script type="text/javascript">

    function passNameArrays(firstNames, lastNames) {
        alert(firstNames.item(0));
    }
</script>

And now, you should see an alert with the text "John". All the rest of the functions like count, indexOf etc. are available from JavaScript.

I have implemented the class as IList(Of String), but you could implement it as IList(Of Object) and pass any type of array (as long as they are COM visible).

An important fact to remember

One important fact which most developers should be aware of is that you are not bound to pass a set number of arguments to the JavaScript function. You could pass any number of arguments to the JavaScript function, e.g., our last JavaScript function could be written and used like this:

<script type="text/javascript">
    function passNameArrays() {
        alert(arguments[0].item(0));
    }
</script>

Passing arguments from JavaScript to VB.NET functions

We have spend enough time passing arguments to JavaScript. Let's move on to the next step, passing arguments to VB.NET functions. You could simply do it like this in JavaScript:

<script type="text/javascript">
    function sendPerson() {
        window.external.sendPerson("John", "Smith", 26);
    }
</script>

and on your VB.NET side, you could define the function to receive these arguments, like:

Public Sub sendPerson(ByVal firstName As String, _
           ByVal lastName As String, ByVal age As Integer)
    MsgBox(String.Format("First name: {0} Last Name: {1} Age: {2}", _
                         firstName, lastName, age))
End Sub

and you are done.

Again, you are not bound to pass simple types as arguments. You could pass JavaScript objects as arguments, if required. Take a look at the last example in a different way. The JavaScript will be:

<script type="text/javascript">
    function sendPerson() {
        var person = new Array();
        person["firstName"] = "John";
        person["lastName"] = "Smith";
        person["age"] = 26;
        window.external.sendPerson(person );
    }
</script>

and you can use the Person object on the VB.NET side, like:

Public Sub sendPerson(ByVal person As Object)
    MsgBox(String.Format("First name: {0} Last Name: {1} Age: {2}", _
           person.firstName, person.lastName, person.age))
End Sub

similar example but different method to achieve the same result.

Returning values from functions

Returning a value from a JavaScript function to VB.NET

What about returning a value from functions? Simple, you could easily get the value from a JavaScript function; e.g., if we call this line in VB.NET:

Dim str As String = _
    Me.WebBrowser1.Document.InvokeScript("getJavascriptString")
MsgBox(str)

and in JavaScript, we could write the function to return a string like:

<script type="text/javascript">
    function getJavascriptString() {
        return "String returned from javascript";
    }
</script>

Again, you are not bound to simple types. You can return your custom JavaScript objects very easily. E.g., let's create a Person class in JavaScript this time, and write a function which will return the Person object back to VB.NET.

<script type="text/javascript">
    function person(name,age) {
        this.name = name;
        this.age = age;
        this.getName = function() {  return this.name; }
        this.getAge = function() { return this.age; }
    }
    
    function getPersonObject() {

        myPerson = new person("Chris McCreadie", 48);
        return myPerson;
    }
</script>

On your VB.NET side, you can do something like this (must warn you the code below is not going to work):

Dim jsPerson As Object = Me.WebBrowser1.Document.InvokeScript("getPersonObject")
MsgBox(String.Format("Name: {0} Age:{1}", jsPerson.getName(), jsPerson.getAge()))

If you try the above code, the first line will run fine, but at runtime (as it is late binding), you'll receive an exception on the second line. If you are asking why it doesn't work, frankly speaking, I don't know, but if you know the answer, you are welcome to explain it.

So, what is the solution? The solution is pretty simple. You take help from System.Reflection, and modify the above code to something like this:

Dim jsPerson As Object = Me.WebBrowser1.Document.InvokeScript("getPersonObject")
Dim jsPersonType As Type = jsPerson.GetType()
Dim name As String = jsPersonType.InvokeMember("getName", _
         Reflection.BindingFlags.InvokeMethod, Nothing, jsPerson, Nothing)
Dim age As Integer = jsPersonType.InvokeMember("getAge", _
        Reflection.BindingFlags.InvokeMethod, Nothing, jsPerson, Nothing)
MsgBox(String.Format("Name: {0} Age: {1}", name, age))

The above code should work perfectly and give you the desired results. I won't go in to the details of explaining the InvokeMember function, there's plenty of help on MSDN and Google for that.

What's the next step now? We can access simple types and complex (custom) types. Can we access the objects (HTML buttons, text fields, div) on the page? Yes, we can. And surprisingly, they are easier to access. Let's pull our sleeves and write a simple function in JavaScript which will return a Button object which happens to be on the page.

<script type="text/javascript">
    function getHtmlButton() {
    //assuming there's a button with id myBtn on the page
        return document.getElementById('myBtn');
    }
</script>

Now, on the VB.NET side, we could do something like this:

Dim htmlButton As Object = Me.WebBrowser1.Document.InvokeScript("getHtmlButton")
htmlButton.value = "Set from vb.net"

The above code will change the button text to "Set from vb.net". We could slightly improve the above code by doing a couple of things:

What these changes will do is, firstly, it will make our htmlButton object a strongly type one instead of the Object type. Secondly, you'll get intellisence from Visual Studio, and it will make your job easier in trying to figure out what method/properties to call/set on the htmlButton.

I would give another example just to show the possibilities.

'assuming JavaScript got a function which will return a div on the page
Dim htmlDiv As mshtml.HTMLDivElement = _
    Me.WebBrowser1.Document.InvokeScript("getHtmlDiv")
htmlDiv.style.background = "Red"

Most of the types in MSHTML are self explanatory, and you can guess what will be converted from the HTML to the MSHTML type. But if you can't tell, here's a small tip: Set your variable to type Object initially, and once you have received an HTML object from JavaScript (assuming you've setup a break point), hover your mouse over it and Visual studio will let you know the exact type, or alternatively, you can look in the Autos or Local window in Visual Studio.

A tip: All (most) developers know this, but if anyone doesn't, here is a little tip if you want more than one value back from JavaScript. If you are passing objects, JavaScript can modify those objects. If we take the example where we created a list(of String) in VB.NET and if we need to get the list of first names and last names from JavaScript, we could do something like this:

Dim firstNames As New myArr()
Dim lastNames As New myArr()
Me.WebBrowser1.Document.InvokeScript("getNames", _
               New Object() {firstNames, lastNames})

and on the JavaScript side, we could do something like:

function getNames(firstNames, lastNames) {
    firstNames.add("John");
    firstNames.add("Chris");
    lastNames.add("Martin");
    lastNames.add("Churn");
}

and as a result, we could easily get multiple values back from JavaScript. I agree this is not the best example, but I hope you get the concept I am trying to explain.

Returning a value from a VB.NET function to JavaScript

I am sure I don't need this section, but just for completeness, I'll give an example here. On the VB.NET side, we could write a simple function to return the current date and time like:

Public Function getCurrentTime() As DateTime
    Return DateTime.Now
End Function

and on the JavaScript side:

function getCurrentTime() {
    alert(window.external.getCurrentTime());
}

Ask me a question :-) I know you must be asking a question right now. Have I done some mistake or submitted an incomplete code? How can I return a DateTime from VB.NET when it is not a simple type and I haven't added any wrapper class around it? The answer is it's a fully working code, and even though DateTime is not a simple type, it's one of the special types which automatically get converted to the JavaScript Date type. Every other concept in returning values from VB.NET is explained above, and I don't think any further explanation is needed. You can return string, integer, boolean, datetime, without any special arrangements, but for other types, you'll have to expose the type/class to COM for it to be visible.

Exception handling

So far, all the examples I have done (for simplicity), I haven't done any exception handling, but that doesn't mean in a production code you'll be doing this. Every call from one platform to the other must be done with an assumption that it wont' work and something at some point will go wrong. As JavaScript is an interpreted language, even if there's some mistake in the script, it might not be visible until runtime when you call JavaScript from your VB.NET code. Similarly, when you call VB.NET from JavaScript, if an exception is thrown from the VB.NET function, it won't crash your program/exe but will be thrown back to the JavaScript and you'll get a JavaScript error dialog from Internet explorer.

Handle VB.NET exceptions in JavaScript

Coming very soon...

Handle JavaScript exceptions in VB.NET

Coming very soon...

Event Handling

Handling VB.NET events from JavaScript

Coming soon...

Handling JavaScript events from VB.NET

Coming soon...

Points of interest

Coming very soon...

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralC# code
forkus2000
7:02 5 Feb '10  
Hi guys ; I have the same problem, i want to communicate a desktop application witha a javascript code, but i can`t find a c# code to doit,

Please someone put a c# code to doit...

Regards Paolo
AnswerRe: C# code
Qaiser_Iftikhar
10:42 18 Feb '10  
Any code shown in this article can easily be translated to C#.

Go to http://www.developerfusion.com/tools/convert/vb-to-csharp/ for conversion.
GeneralVery Good Job
narvis25
8:39 12 Jan '10  
Your article is very helpfull

Thanks a lot !!!

Eric
Generalanswer this question
Member 6656753
23:09 23 Oct '09  
driving license (class)
+number: string (constructor)
+renewelperiod: int (constructor)
+ GetLicenseInfo():void (mrthod)
+ CalculateLicensePrice(): double (method)
+ DisplayLicenseInfo() : void (method)


Based on the above, create a program with the following requirement
• GetLicenseInfo() method that input license number and renewal period from user. Display an information to the user either to renew the license for 1,2,3 or 5 years.
• CalculateLicensePrice() method that will calculate price for driving license depends on the renewal period of 1,2,3 or 5 years. The renewal fee is RM30 per year
• A method DisplayLicenseInfo() that will display each details including license number,renewal period and license price.

Create an object and invoke necessary method
GeneralRe: answer this question
nagendrathecoder
23:30 23 Oct '09  
nobody is gonna do that.Thumbs Down
GeneralRe: answer this question
Dave Kreskowiak
4:03 24 Oct '09  
Anyone who did this for you would be an idiot. The whole point of having this assignment is so you can demonstrate you have to skills to do it. If you can't do it, then you don't deserve to pass.

Yes, we will help you, but only if you have specific questions about where you're getting stuck. Just asking someone to do your work for you is just going to get you ignored.

A guide to posting questions on CodeProject[^]
Dave Kreskowiak
Microsoft MVP
Visual Developer - Visual Basic
     2006, 2007, 2008
But no longer in 2009...


GeneralWithout a Browser Control?
cjbarth
13:11 23 Oct '09  
Do you know of a way of accomplishing this without a browser control? The reason that I'm asking is that I need to aggregate data from a third party via a window-less routine. The code is working fine form an HTML page, but that doesn't allow me to interact like I need to.

My vision is to have a class (DLL) that I can simply make a call to and it will return the data that is harvested by the third-party JavaScript.

If you want an example of what I'm talking about see: https://il.thewattspot.com/PriceBanner.jsp[^]

You can see that nicely formatted data is displayed. Now what I need is a class that I can call that will return that data for consumption by other programs. Any ideas?

Chris Barth
AnswerRe: Without a Browser Control?
Qaiser_Iftikhar
2:11 29 Oct '09  
Well the easiest solution is to use httpwebrequest and try to replicate the logic in Javascript to get the information you need.

More info on httpwebrequest can be found here http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx
GeneralI'll also say brilliant!
dbassett74
13:53 15 Oct '09  
This is an awesome article and I encourage you to complete the rest on events and exception handling.
GeneralRe: I'll also say brilliant!
Qaiser_Iftikhar
3:06 20 Oct '09  
Thanks for your positive feedback. Well completing the article is on my TODO list, I hope to complete it as soon as I have some free time.
QuestionWebBrowser.ObjectForScripting Property not available to me, help!
charanyabs
14:34 10 Aug '09  
I used your code to communicate between java script and ASP.NET.

I am trying access ASP.NET from java script

My code in ASP .NET
_
_

But to expose my form,
Me.webBrowser1.ObjectForScripting = Me is not available to me.

I dont have a webBrower added to my form. This is already existing form and i can not add a
web brower to it.

How do i make this form public and make it available to my java script?

Please help! its urgent.

Thanks
AnswerRe: WebBrowser.ObjectForScripting Property not available to me, help!
Qaiser_Iftikhar
9:02 11 Aug '09  
Hi,

I am sorry but this is not going to work in Asp.net.

The article is intended for vb.net/c# Winform and not for asp.net.
Generalerror run-time
Member 1254160
0:18 22 Jul '09  
I tried to use the script:

<script type="text/javascript>
showVbHelloWorld function () (
window.external.showVbHelloWorld ();
)
</script>;

The function showVbHelloWorld is in the code-behind page asp.

testing with visual studio 2008 gives me the error Run-time object does not exist on line: window.external.showVbHelloWorld.

why
AnswerRe: error run-time
Qaiser_Iftikhar
10:41 22 Jul '09  
First of all let me clarify this is that this article is not about asp/asp.net. You can use asp/asp.net if the webpage is displayed in a custom application (not a regular browser).

If you run this in a normal browser, it won't work as the host for your page is a simple browser and it hasn't exposed the function showVbHelloWorld. You need to run it in a custom application which has exposed the object with function showVbHelloWorld.

Qaiser.
GeneralOMG - Wow
keggfyoid
13:41 7 Jul '09  
<b>You Sir, are an absolute genius Smile )))))))))))))))))))</b>

I was going mad trying to do this in ASP.NET, trying to invoke javascript from server side code and pass variables back and forth, and you have provided my exact solution in a VB.NET windows application, which is my preferred platform.

Whatever you get paid, it should be doubled, nay tripled.

What a superb tutorial: A++++++++++++++++++++++

p.s. Thanks again Smile

Here's my [mypage.html] contents verbatim, for people who may struggle with the exact syntax:

<html>
<body>

<script type="text/javascript>;
      function showJavascriptHelloWorld() {
            alert("Hello world from web page!!!!!!!!!!!!!!");
      }
</script>

<script type="text/javascript">
      function showVbHelloWorld() {
            window.external.showVbHelloWorld();
      }
</script>


<input type="submit" id="MyCustomButton" value="MyButton" runat="server" OnClick="showVbHelloWorld()">

</body>
</html>
GeneralQuick question
merledog
11:13 15 Jun '09  
First off great article.

I'm a java developer dabbling in VB so I'm a little out of my element.

My app runs like this:

1-Call VB sub from javascript
2-VB sends info back to javascript function.
3-javascript function called from VB via InvokeScript contains more window.external VB calls. At this point I get an error stating "Object reference not set to an instance of an object." Not sure what this means because the same VB Function is called through the javascript earlier in the program and works fine. Confused

Any help would be greatly appreciated
GeneralRe: Quick question
Qaiser_Iftikhar
1:59 18 Jun '09  
Hi,

Your problem seems to be the object being not initiated. E.g in Java if you do

MyClass x;
x.somefunction();
assuming somefunction is a function of class MyClass. In java you'll get an error as object x is null. If you post your code I might be able to tell where the problem is but from the error you told it's related to a function being called on object which is null.


Qaiser.
QuestionMay I translate your article and publish it on my site? [modified]
Rodrigo Salvaterra
8:07 12 May '09  
Hi,

Congratulations! Very good article!
May I translate it to Portuguese-BRL and publish on my site:

http://www.iguru.com.br


Thank you,
Rodrigo

modified on Tuesday, May 12, 2009 8:58 PM

AnswerRe: May I translate your article and publish it on my site?
Qaiser_Iftikhar
9:51 12 May '09  
Hi,

Thanks for your interest. I don't have any problem in that as long as you mention the link to the original article in your translated version.

BTW article is unfinished yet. I'm hoping to finish rest of the sections by the end of this month when I got couple of days off from work.

Qaiser.
QuestionActivex Dialog
mrcouthy
19:55 21 Apr '09  
Hi You have done a brilliant work n thanks a lot I have tried it by self too...
However My JavaScript contains access to file system
<script language="JavaScript"> <!--
var fso = new ActiveXObject("Scripting.FileSystemObject");
--> </script>
And this particular code is producing a "An Activex control in this page might be unsafe..." Dialog box which is very annoying.
It would be much useful if you could devise way to suppress this dialog.
AnswerRe: Activex Dialog
Qaiser_Iftikhar
23:16 21 Apr '09  
Hi,

To avoid the dialog, the eaisest solution will be for your end-user to add your site to trusted sites and lower the security settings for Trusted Sites in Internet Explorer options. The dialog won't appear in that case.

I hope this helps.
GeneralBrilliant!!!
Zodraz
11:31 21 Apr '09  
Wow brilliant, fantastic!
Recently I've done a project interacting Winform and an API which was designed only with js to ease development, and I've done so tricky things to interact between them...
Your article has clarified me so many things(a little late to refactor my code...). However fantasctic and brilliant!I am expecting to see the next posts!!!!

Thanks!!!!

Zodraz
GeneralRe: Brilliant!!!
Zodraz
11:36 21 Apr '09  
Of course a 5 is for you!!!
GeneralRe: Brilliant!!!
Qaiser_Iftikhar
23:29 21 Apr '09  
Thanks for your positive response. That will drive me towards finishing rest of the sections ASAP.
GeneralVote of 5
icetea94
7:49 15 Apr '09  
Hi,
great example. I found it very useful and now, we use it to access a desktop-application from a web-application.


Last Updated 19 Apr 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010