Fabulous Adventures In Coding

Eric Lippert's Blog

JScript and VBScript Arrays

 

 

Earlier I alluded to the fact that JScript arrays are objects but VBScript arrays are not.  What's up with that?

 

It's kind of strange.  Consider the properties of a JScript array.  A Jscript array is

 

* one dimensional.

* associative; JScript arrays are indexed by strings.  Numeric indices are actually converted to strings internally.

* sparse: arr[1] = 123; arr[1000000] = 456; gives you a two-member array, not a million-member array.

* an object with properties and methods.

 

Whereas a VBScript array is

 

* multi-dimensional

* indexed by integer tuples

* dense

* not an object

 

It is hard to come up with two things that could be more different and yet both called "array".

 

As you might expect, JScript and VBScript arrays have completely different implementations behind the scenes.  A JScript array is basically just a simple extension of the existing JScript expando object infrastructure, which is implemented as a (rather complicated) hash table.  A VBScript array is implemented using the SAFEARRAY data structure, which is pretty much just a structure wrapped around a standard "chunk of memory" C-style array.

 

Since all the COM objects in the world expect VBScript-style arrays and not JScript-style arrays, making JScript interoperate with COM is not always easy.  I wrote an object called VBArray into the JScript runtime to translate VBScript-style arrays into JScript arrays, but it is pretty kludgy.  And though I wrote some code to go the other way -- to turn JScript arrays into VBScript arrays -- there were just too many thorny issues involving object identity and preservation of information for us to actually turn it on.  There weren't exactly a whole lot of users demanding the feature either, so that part of the feature got cut.  (If I recall correctly, my colleague Peter Torr wrote some COM code to do that before he came to work at Microsoft.  He might still have it lying around.)

 

Things got even weirder when I wrote the code to interoperate between CLR arrays and JScript .NET arrays, but that's another story.

 

Published Monday, September 22, 2003 1:55 PM by Eric Lippert

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Deadprogrammer said:

Why are there two types of multidimentional arrays? What is the difference between the (x)(y) and (x,y) notation? dim arrBar arrBar = Array(Array(1,2), Array(3,4)) response.write arrBar(0)(0) & "<BR>" response.write arrBar(0)(1) & "<BR>" response.write arrBar(1)(0) & "<BR>" response.write arrBar(1)(1) & "<BR>" dim arrFoo (1,1) arrFoo (0,0) = 1 arrFoo (0,1) = 2 arrFoo (1,0) = 3 arrFoo (1,1) = 4 response.write arrFoo(0,0) & "<BR>" response.write arrFoo(0,1) & "<BR>" response.write arrFoo(1,0) & "<BR>" response.write arrFoo(1,1) & "<BR>" 'these don't work response.write arrFoo(0)(0) response.write arrBar(0,0)
September 22, 2003 6:04 PM
 

priya said:

ya google is realy more used me , here lot of answer is described simple way to understand
thanks ur website help
February 11, 2004 6:32 AM
 

Daren said:

I understand the issues with converting an existing JScript array to a VBArray. But would it be possible to include within JScript an straight forward way to create a new VBArray?

For example, I am trying to execute IADs::GetInfoEx( <vbarray>, 0 ); I have tried every which way to create a valid VBArray this method will actually accept, such as using the Scripting.Dictionary - Items() method. No such luck. In the end I had to convert the script to wsf and write a VB Function to handle this part, while the rest is in JScript.

It would be nice to natively and easily create these types of objects..

Thanks,
Daren

May 20, 2004 9:49 AM
 

Eric Lippert said:

Yes, it would be nice. Unfortunately, I never did get around to implementing that in JScript Classic. Sorry about that.

I did add much better support for arrays in JScript .NET though. (Small consolation, I know.)
May 20, 2004 9:54 AM
 

David Karlton said:

I'm one of those crazed users who's trying to figure out how to pass a JScript array argument to C# code. If I cast the argument as an object, its type is System.__COMObject, so I assume I need to marshal it somehow.

I currently am exposing JScript methods to my C# code by implementing a subclass of IDispatch, called ICustomMethods, and registering my C# application:

public void GetExternal([MarshalAs(UnmanagedType.IDispatch)] out object ppDispatch)
{
ppDispatch = this as ICustomMethods;
}

From JScript, it just requires calling

window.external.MyCustomMethod(...);

So, the problem is that one of these JScript methods I need to support has a JScript array argument, and I don't know how to marshal it.

Any ideas?

Thanks much!

David
April 19, 2005 8:19 AM
 

Eric Lippert said:

A JScript array is a dispatch object which when invoked on its indexes, gets/sets the results.

In C++ what you'd do to simulate arr[123], for instance, is you'd get the dispid for "123", and invoke on that dispid.

How you're going to do that in C# beats the heck out of me. We designed JScript arrays years before C# was a gleam in Anders' eye. If you figure something out, let me know.
April 19, 2005 3:08 PM
 

Bim Jeam said:

Something like this works for me


In Html file's Javascript

window.external.ArrayReceivingFunction(['Arg1', 'Arg2', 'Arg3',etc.]);


My C# "window.external" class

public class WindowExternal
{
public void ArrayReceivingFunction(object argArray)
{
object[] objArr = DispatchHelpers.GetObjectArrayFrom__COMObjectArray(argArray);
}
}


My C# Dispatch Helpers class

internal class DispatchHelpers
{
internal static object[] GetObjectArrayFrom__COMObjectArray(object comObject)
       {
           int length = Convert.ToInt32(GetPropertyValue(comObject, "length"));
           object[] objArr = new object[length];
           for (int idx = 0; idx < length; idx++)
           {
               objArr[idx] = GetPropertyValue(comObject, idx.ToString());
           }

           return objArr;
       }

internal static object GetPropertyValue(object dispObject, string property)
       {
           object propValueRef = null;
           try
           {
               Type type = dispObject.GetType();
               propValueRef = type.InvokeMember(property, BindingFlags.GetProperty,
                                               null, dispObject, null);
           }
           catch (COMException) { /* Throws COMException on invalid property */ }

           return propValueRef;
       }
}
March 5, 2006 7:28 PM
 

Bim Jim said:

By the way Eric your info "A JScript array is a dispatch object which when invoked on its indexes, gets/sets the results." was invaluable assistance
March 5, 2006 7:35 PM
 

Jim d said:

Hey, so I think I managed to hack together an okay solution.  It requires a bit of juggling but it manages to preserve elements' datatypes (for primitives only).  Basically you create vbscript functions for manipulating the VBScript array, and then a JScript function which calls these manipulation functions..

Here's the vbscript code:

 '  return a blank dynamic array
 function getBlankArray()
   getBlankArray = Array()
 end function

'  append  arr with the specified val
 function appendArray(arr, val)
   redim preserve arr(ubound(arr) + 1)
   arr(ubound(arr)) = val
   appendArray = arr
 end function

And here's the JScript portion.  I extended the Array class, but you could have a seperate function.

 Array.prototype.toVBArray = function() {
   //call our vbscript function to give us a blank VBArray
   var vbarray = getBlankArray();
   for(var i = 0; i < this.length; i++)  {
     //use our vbscript manipulation function to append the ith item
     vbarray = (appendArray(vbarray, this[i]));
   }
   return(vbarray);
 }    

With that in place,  you should be able to convert simple jscript arrays  to VBArrays, a la
 var tmp = [1, 2, 3.14, 'hi mom'];
 tmp.toVBArray();

April 19, 2006 4:59 PM
 

eric neville said:

Playing with jscript here, and wondering if there's a way to get at the KEYS of a jscript associative array from vbscript.  MSE7 seems to know what the keys are, and using For Each, i seem to be able to iterate the VALUES in the array, but I can't seem to hit the keys, though the IDE seems to know they're there.

Am I out of luck with this one?  I know it's probably a long shot...
August 14, 2006 6:11 PM
 

Eric Lippert said:

You are out of luck.  There is no equivalent to the JScript for-in in VBScript.  Sorry!

August 14, 2006 9:18 PM
 

Jaiprakash said:

Recently I investigated a bug in Jscript which was reported on Vista. The scenario was working perfectly

January 9, 2007 1:15 PM
 

nAty said:

I have the same problem that David Karlton, but the only difference is that my array has two different dimensions.

Here is the example:

<script language="javascript" type="text/javascript">

     function Array2D(dim1, dim2)

     {

       for (var i = 0; i < dim1; ++i)

       {

           this[i] = new Array(dim2);

       }

       this.length = new Array(dim1, dim2);

     }

function LoadPage()

    {

      var mat= null;

      mat=new Array(5,2);

      var name = '30';

var ar = new Array2D(5,2);

       ar[0][1] = "Dato1";

       ar[0,1]= 10;

       ar[1,0]= "Dato2";

       ar[1,1]= 20;

       ar[2,0]= "Dato3";

       ar[2,1]= 30;

       ar[3,0]= "Dato4";

       ar[3,1]= 40;

       ar[4,0]= "Dato5";

       ar[4,1]= 50;

       for (i=0;i<=4;i++)

       {

        ar[i,0]= 'dato'+i;

        ar[i,1]= (i+1)*10;

       }

       if(ar!=null)

       {

       obj=document.getElementById('TestDll');

       mat = obj.LoadPage('30',mat); //Here is the problem

}

</script>

I need to know if is possible to cast the mat array and bidimensional array that that was sent to C# like parameter in LoadPage Function, and How can I do this? I receive an object of type System.__COMObject but I need a type object [,] in C#.

December 12, 2007 4:44 PM
 

futureprogramming.com &raquo; Blog Archive &raquo; Ajax said:

May 6, 2008 3:02 AM
 

agent009 said:

Here's a simple VBScript function that converts single-dimension JScript array to VBArray:

<script language="VBScript">

Function toVBArray (ByRef jsa)

  Dim e, i, vba()

  i = 0

  For Each e In jsa    

     ReDim Preserve vba(i)

     vba(i) = e

     i = i + 1

  Next

  toVBArray = vba

End Function

</script>

In fact it can be used on any object, but you will lose property names. It will also skip "gaps" in sparse JScript arrays.

You can call it from either JScript or VBscript functions. You can create similar functions for converting more dimensions into arr(1,2,3,...) style arrays by nesting For Each loops - it will require separate function for each given number of dimensions though.

arr(1)(2)(3) style VBArrays can be created by modifying this function to call itself recursively (number of dimensions of JScript array would have to be provided as additional argument since there's no way to reliably determine it programmaticaly).

June 4, 2008 5:50 PM
 

Pascal Lev92 said:

The method from Bim Jim seems good, however I received objects System.__COMObject by reference and I don't know how to get their value (as string for example).

Is someone has an idea ?

July 2, 2008 1:38 PM
 

Rex Henderson said:

Adding to agent009 JScript array to VBArray function, I just access JScript arrays using dot notation.

x.[0]  'Access the first element of JScript array within VBScript.

Works on XP SP3/IE 8 anyways.

June 17, 2009 1:08 AM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker