VB.NET/C# and JavaScript communication

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

  • In Visual Studio,create a new WinForms application,name it anything you like.
  • Add an import statement like Imports System.Security.Permissions in your form1 (main form).
  • Add a couple of attributes to form1,like:
    Collapse Copy Code
    <PermissionSet(SecurityAction.Demand,Name:="FullTrust")> _
    <System.Runtime.InteropServices.ComVisibleAttribute(True)> _
    Public Class Form1
    End Class

    All they do is tell the .NET Framework that we want fulltrust and make the class visible to COM so this class is visible to JavaScript.

  • Add a Webbrowser control to the form and set its url property to c:/temp/mypage.html (just an example path,you should set it to the HTML page you'll be using).
  • Add a Button control on the form,and on its click handler,write this code:
    Collapse Copy Code
    Private Sub Button1_Click(ByVal sender As System.Object,_
                ByVal e As System.EventArgs) Handles Button1.Click
        Me.Webbrowser1.Document.InvokeScript("showJavascriptHelloWorld")
    End Sub
  • In your HTML page,add this code:
    Collapse Copy Code
    <script type="text/javascript">
        function showJavascriptHelloWorld() {
            alert("Hello world");
        }
    </script>

Calling VB.NET from JavaScript

  • Continuing with the last project,add the following lines of code in your form1:
    Collapse Copy Code
    Public Sub showVbHelloWorld()
        MsgBox("Hello world")
    End Sub
  • In your form1 load event,add this line of code:
    Collapse Copy Code
    Me.Webbrowser1.ObjectForScripting = Me

    What this line does is,it exposes your form1 class to the JavaScript on the HTML page. You Could expose any class as long as you make it visible to COM and set its permission to fulltrust.

  • In your HTML page,add a Button,and on its click event,call this function:
    Collapse Copy Code
    <script type="text/javascript">
        function showVbHelloWorld() {
            window.external.showVbHelloWorld();
        }
    </script>
  • That is it. We've accomplished two way communication. But,most developers must have seen similar examples on MSDN or in different forums. This is just the starting point,our next step is to pass arguments to the functions.

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:

Collapse Copy Code
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:

Collapse Copy Code
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.:

Collapse Copy Code
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:

  • Create a class called Person,like:
    Collapse Copy Code
    <PermissionSet(SecurityAction.Demand,Name:="FullTrust")> _
    <System.Runtime.InteropServices.ComVisibleAttribute(True)> _
    Public Class Person
        Public Sub New(ByVal firstName As String,_
               ByVal lastName As String,ByVal age As Integer)
            Me._firstName = firstName
            Me._lastName = lastName
            Me._age = age
        End Sub
    
        Private _firstName As String
        Private _lastName As String
        Private _age As Integer
    
        Public Function getFirstName() As String
            Return Me._firstName
        End Function
    
        Public Function getLastName() As String
            Return Me._lastName
        End Function
    
        Public Function getAge() As Integer
            Return Me._age
        End Function
    
    End Class
  • In your form1,call it like this:
    Collapse Copy Code
    Me.Webbrowser1.Document.InvokeScript("sendPerson",_
       New Person() {New Person("John","Smith",37)})
  • In your JavaScript,you can use the Person object like:
    Collapse Copy Code
    <script type="text/javascript">
        function sendPerson(person) {
            alert("First Name:" + person.getFirstName() + 
                  "Last Name:" + person.getLastName() + 
                  "Age:" + person.getAge());
        }
    </script>
  • Most developers should be aware of this,but I must point out that when you pass your object to JavaScript,it is fully exposed (all public methods/properties),and JavaScript can modify your object. As an example,if I add this function in my Person class:
    Collapse Copy Code
    Public Sub setFirstName(ByVal firstName as String)
        Me._firstName=firstName
    End Sub

    Now,in your JavaScript,modify the function sendPerson like:

    Collapse Copy Code
    function sendPerson(person) {
        person.setFirstName('Roger');
    }

    After this call,your person will have first name as 'Roger' instead of 'John'. To avoid this situation,there are two options. Make setFristName private/protected,but that means you won't be able to access this method from VB.NET. The better solution is to add an attribute to setFirstName,like:

    Collapse Copy Code
    <System.Runtime.InteropServices.ComVisibleAttribute(False)> _
    Public Sub setFirstName(ByVal firstName as String)
        Me._firstName=firstName
    End Sub

    Now,your function is visible in your VB.NET code,but JavaScript won't be able to call it,and as a result modify it in case you don't want to expose a particular method to JavaScript for any reason.

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:

Collapse Copy 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:

Collapse Copy Code
<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:

Collapse Copy Code
<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:

Collapse Copy Code
Dim firstNames As New myArr(New String() {"John","Micheal"})
Dim lastNames As New myArr(New String() {"Smith","Day"})
Me.Webbrowser1.Document.InvokeScript("passNameArrays",_
               New Object() {firstNames,you Could use it like:

Collapse Copy Code
<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:

Collapse Copy Code
<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:

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

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

Collapse Copy Code
Public Sub sendPerson(ByVal firstName 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:

Collapse Copy Code
<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:

Collapse Copy Code
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:

Collapse Copy Code
Dim str As String = _
    Me.Webbrowser1.Document.InvokeScript("getJavascriptString")
MsgBox(str)

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

Collapse Copy Code
<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.

Collapse Copy Code
<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):

Collapse Copy Code
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:

Collapse Copy Code
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)
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.

Collapse Copy Code
<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:

Collapse Copy Code
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:

  • Add a reference in your project for "Microsoft HTML Object Library",can be found under the COM section.
  • And Now,change the first line of the above code to:
    Collapse Copy Code
    Dim htmlButton As mshtml.HTMLInputElement = _
        Me.Webbrowser1.Document.InvokeScript("getHtmlButton")

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.

Collapse Copy Code
'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:

Collapse Copy Code
Dim firstNames As New myArr()
Dim lastNames As New myArr()
Me.Webbrowser1.Document.InvokeScript("getNames",lastNames})

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

Collapse Copy Code
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:

Collapse Copy Code
Public Function getCurrentTime() As DateTime
    Return DateTime.Now
End Function

and on the JavaScript side:

Collapse Copy Code
function getCurrentTime() {
    alert(window.external.getCurrentTime());
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")