6

I need to pass an array of int or long (doesn't matter) from a VB6 application to a C# COM Visible class. I've tried declaring the interface in C# like this:

void Subscribe([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)]int[] notificationTypes)

void Subscribe(int[] notificationTypes)

But both of them raised a Function or interface markes as restricted, or the function uses an Automation type not supported in Visual Basic.

How should I declare the C# method?

Basic
  • 26,321
  • 24
  • 115
  • 201
Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207
  • Hmm, this is odd. Just remove the [MarshalAs], the array is already marshaled as a SAFEARRAY without your help. We need to see the rest of the interface type if you still have trouble. – Hans Passant Jul 13 '12 at 12:45
  • @HansPassant Yes, I took a look at the generated IDL as it is correctly declared as a SAFEARRAY(long) on both cases so I presume it has to be a problem related with VB6. I'm still investigating. – Ignacio Soler Garcia Jul 13 '12 at 13:38
  • Does this answer your question? [Pass an array from vba to c# using com-interop](https://stackoverflow.com/questions/2027758/pass-an-array-from-vba-to-c-sharp-using-com-interop) – GSerg May 22 '22 at 11:39
  • @GSerg to be honest I made the question 9 years ago, I do not work with these technologies a while ago. The answer looks good though. – Ignacio Soler Garcia May 25 '22 at 13:39
  • 1
    @IgnacioSolerGarcia That's fine, it's not as much to answer your question, but to link these several questions together for future readers. – GSerg May 25 '22 at 13:50

2 Answers2

1

If you get desperate, code the signature in a dummy VB6 ActiveX dll project. Then generate the .NET Interop version of the vb6 component via Visual studio or the command line tool. Then use Reflector or dotPeek to pull the code out of the interop assembly. It is the long way around, but it works.

tcarvin
  • 10,715
  • 3
  • 31
  • 52
-1

I ran into this problem 9 years later. The solution I came up with is to pass a pointer to the first element of the array, along with the upper bound (UBound in VB6). Then iterate the pointer to the upper bound and put each element into a list.

on the vb6 side use

    Dim myarray(3) As float
    Dim ptr As integer
    Dim upperbound as integer

    myarray(0) = 0.1
    myarray(1) = 0.2
    myarray(2) = 0.3
    myarray(3) = 0.4

    ptr = VarPtr(myarray(0))
    upperbound = UBound(myarray)

    SetMyFloat(ptr, upperbound)
    

C# code


    public float MyFloat {get; set;}

    public unsafe void SetMyFloat(float* ptr, int ubound)
    {
        MyFloat = PointerToFloatArray(ptr, ubound);
    }

    public unsafe float[] PointerToFloatArray(float* ptr, int ubound)
    //this is to deal with not being able to pass an array from vb6 to .NET
    //ptr is a pointer to the first element of the array
    //ubound is the index of the last element of the array
    {
        List<float> li = new List<float>();
        float element;
        for (int i = 0; i <= ubound; i++)
        {
            element = *(ptr + i);
            li.Add(element);
        }
        return li.ToArray();
    }