4

I have a .NET class which holds a simple array of strings available via an accessor method, which looks like this;

namespace Foo.Bar {
    [ComVisible(true)]
    [Guid("642279A0-85D4-4c7a-AEF5-A9FAA4BE85E5")]
    public class MyClass {
        private string[] _myArray;
        public MyClass() { }

        public MyClass(string[] myArray) {
            _myArray = myArray;
        }

        public string[] MyArray {
            get { return _myArray; }
        }
    }
}

I consume this class using Classic ASP;

Dim foo 
Set foo = Server.CreateObject("Foo.Bar.MyClass")

if IsArray(foo.MyArray) then Response.Write("IsArray") & "<br />"
Response.Write(typename(foo.MyArray)) & "<br />"
Response.Write(UBound(foo.MyArray)) & "<br />"

This results in;

IsArray
String()
1

However, when I try to access the contents of the array using;

Response.Write(foo.MyArray(0)) & "<br />"

I get;

Microsoft VBScript runtime (0x800A01C2) Wrong number of arguments or invalid property assignment: 'MyArray'

Any help is much appreciated.

Edit This is to provide more information after digesting the answers given (thanks)

When changing the implementation of the MyArray property to;

public object[] MyArray {
    get { return (object[])_myArray; }
}

I then get the following error,

Microsoft VBScript runtime (0x800A000D) Type mismatch: 'MyArray'

So I tried individually casting each string to an object;

public object[] MyArray {
    get {
        object[] tmp = new object[_myArray.Count()];
        for (int x = 0; x < _myArray.Count(); x++) {
            tmp[x] = (object)_myArray[x];
        }
        return tmp;
    }
}

Then I'm back to,

Microsoft VBScript runtime (0x800A01C2) Wrong number of arguments or invalid property assignment: 'MyArray'

Edit Final solution with help from How to correctly marshal VB-Script arrays to and from a COM component written in C#

C#

public object MyArray {
    get { return _myArray.Cast<object>().ToArray(); }
}

VBScript

Dim foo 
Set foo = Server.CreateObject("Foo.Bar.MyClass")

bar = foo.MyArray
Response.Write bar(0)

The key was to expose object rather than object[] and as AnthonyWJones suggested, assign the array to a variable before using it.

Thanks again.

Community
  • 1
  • 1
Red Taz
  • 4,159
  • 4
  • 38
  • 60
  • This gave me the answer I was looking for. Just needed to add using System.Linq to make the cast work – Graham Jun 26 '12 at 16:39

4 Answers4

3

The problem is VBScript cannot actually use an array of String. It can only use an array of Variant.

Try changing MyClass to expose an object[] instead.

AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
  • Is there no way of casting it to an array of `Variant`? I only ask because clearly VBScript 'knows' it's an array, it 'knows' its current type, surely it knows how to cast it? I'd rather not change my .NET implementation just to keep legacy systems happy. – Red Taz Oct 12 '11 at 08:23
  • @Rob2211: You could try assigning the property to VBScript variable and then use the variable. Thinking about it you might need to do that anyway but I still think you going to need to change the interface. It usually not a good idea to expose what you are actually using in a COM interface. Its better that you create a specific set of COM interfaces and classes that implement those interfaces. These classes then wrap and adapter your inner .NET classes. That way you build the COM interfaces in a way compatible with the consumer (VBScript) and yet not comprimise your .NET code – AnthonyWJones Oct 12 '11 at 08:59
  • Thanks for the advice on writing a wrapper, I'll have to rewrite this later. Regardless, VBScript is still unhappy despite the fact the property now exposes `object[]` (see question edit) any thoughts? – Red Taz Oct 12 '11 at 09:15
  • 1
    @Rob2211: Hmm.. sounds like you need to get explict. Another approach is to add the `MarshalAs` attribute to the property. Try specifying `UnmanagedType.SafeArray` as the unmanagedtype and set the `SafeArraySubType` property of the attribute to `VarEnum.VT_VARIANT`. – AnthonyWJones Oct 12 '11 at 16:23
2

In addition to Anthony's suggestion

I'm not sure is it the best way but in the past I used a code similar to the following to handle one dimensional arrays.

public object MyArray(int ix = -1){
    string[] tmp = new string[] {"one", "two", "3", "4"};
    return (ix == -1) ? (object)tmp : tmp[ix];
}

In ASP:

Response.Write(TypeName(foo.MyArray)) 'string()
Response.Write(TypeName(foo.MyArray(0))) 'string
Kul-Tigin
  • 16,728
  • 1
  • 35
  • 64
0

VBScript doesn't understand generic collections such as List<string> and it doesn't understand string arrays either.

I wrote a public function into my Interface class to convert any generic collections into an ArrayList

public ArrayList toArrayList(IEnumerable collection)
{
        var arrayList = new ArrayList();
        foreach (object element in collection)
        {
            arrayList.Add(element);
        }
        return arrayList;
}

This code can then be used in VBScript like this

 dim connector
 set connector = model.getRelationByID(connectorID)
 'get the related elements
 dim relatedElements
 set relatedElements = model.toArrayList(connector.relatedElements)
 addRelatedElementoAutoDiagram relatedElements(0), relatedElements(1), model

The advantage of this approach is that I don't need to change the signature of any of the methods or properties in C#, but I can still use them in VBScript

Geert Bellekens
  • 12,788
  • 2
  • 23
  • 50
-2

This code demonstrates how to handle arrays between COM and ASP:

<% @Language="VBScript" %>
<% Option Explicit %>
<%
Dim tcs
Dim rc
Dim vntInput(0,4)
Dim i

vntInput(0,0) = Request.QueryString("strUser")
vntInput(0,1) = Request.QueryString("intCreate")
vntInput(0,2) = Request.QueryString("intDelete")
vntInput(0,3) = Request.QueryString("intModify")
vntInput(0,4) = Request.QueryString("intView") 

Set tcs = Server.CreateObject("TestCases.ArrayFailure")
rc = tcs.AcceptArray(vntInput)

For i = 0 to UBound(vntInput, 2)
    Response.write "Loop Count " & i & " " & vntInput(0,i) & "<BR>"
Next

%>

Here's a link to the article where I found this code:
http://202.102.233.250/b2000/ASP/articles/component/pv990826.htm

James Johnson
  • 45,496
  • 8
  • 73
  • 110