2

I'm trying to pass an array of integers from Classic ASP to a DLL created in C#.

I have the following C# method:

public int passIntArray(object arr)
{
    int[] ia = (int[])arr;
    int sum = 0;
    for (int i = 0; i < ia.Length; i++)
        sum += ia[i];

    return sum;
}

I've tried a number of ways to convert arr to an int[], but not having any success. My asp code is:

var arr = [1,2,3,4,5,6];
var x = Server.CreateObject("dllTest.test");
Response.Write(x.passIntArray(arr));

I am currently getting the following error:

Unable to cast COM object of type 'System.__ComObject' to class type 'System.Int32[]'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.

Can anyone tell me how to do it or tell me it can't be done?

Using the code on this very useful page http://www.add-in-express.com/creating-addins-blog/2011/12/20/type-name-system-comobject/ I have managed to find out that the type of the passed parameter is "JScriptTypeInfo" if that's of any use.

If I add:

foreach (object m in arr.GetType().GetMembers())
    // output m

I get the following output:

System.Object GetLifetimeService()
System.Object InitializeLifetimeService()
System.Runtime.Remoting.ObjRef CreateObjRef(System.Type)
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Graham
  • 7,807
  • 20
  • 69
  • 114
  • As int[] is marshalled by Com Interop as a SAFEARRAY, this is essentially a duplicate of : http://stackoverflow.com/questions/5910538/how-to-create-a-safearray-in-windows-jscript – Chris Dickson Sep 14 '12 at 12:07
  • If it's a duplicate, then I don't understand it because I don't know how to take the answer from that to make my code work – Graham Sep 14 '12 at 12:19

1 Answers1

1

As explained in the SO item I suggested was a duplicate, you would change your ASP code thus:

function getSafeArray(jsArr) 
{
  var dict = new ActiveXObject("Scripting.Dictionary");     
  for (var i = 0; i < jsArr.length; i++)     
    dict.add(i, jsArr[i]);     
  return dict.Items(); 
} 
var arr = [1,2,3,4,5,6]; 
var x = Server.CreateObject("dllTest.test"); 
Response.Write(x.passIntArray(getSafeArray(arr))); 

You should also change your C# method signature to:

public int passIntArray(object[] arr) // EDITED: 17-Sept

or

public int passIntArray([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_I4)]  int[] arr)

The point is that you are not really trying to go from JavaScript to C#, you are going from JavaScript to COM: you can only interface the C# DLL at all because it is ComVisible and is registered in the COM registry with a ProgID which Server.CreateObject can look up. With the signature change, your DLL's COM-exposed interface will expect to receive an unmanaged SAFEARRAY and the script code above is a way to get JavaScript to provide one, using the COM Scripting.Dictionary as a sort of custom marshaler.

Community
  • 1
  • 1
Chris Dickson
  • 11,964
  • 1
  • 39
  • 60
  • Thanks for explaining it, but it doesn't work. I get error: Microsoft JScript runtime error '800a000d' Type mismatch on the Response.Write line. I have split the line into parts, and it is the x.passIntArray bit that causes the error. Getting the safearray into a variable works fine. – Graham Sep 17 '12 at 09:07
  • Try the amended C# method signature as per my edit above, and see if that calls the C# method successfully. You'll then have to cast the elements to `int` inside the method. (Alternatively you may be able to help the marshaler do the right thing by attributing your C# method argument with `[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_I4)]`) – Chris Dickson Sep 17 '12 at 09:51
  • Where do I put the attribute - I have put it just before the method and it seems to be happy there, but it doesn't like VT_I4 - does not exist in the current context – Graham Sep 17 '12 at 10:39
  • Sorry, that should be `public int passIntArray([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)] int[] arr)`. Note you are attributing the argument, not the method. – Chris Dickson Sep 17 '12 at 11:50
  • That don't work either, but I give up, I'm gonna give it to you as it works without the marshalling, though annoyingly, I have to cast each element to an int – Graham Sep 17 '12 at 12:05