2

Currently I am trying to pass a variant data type array into a c# method through the COM interop. The issue is, passing it as:

[MarshalAs(UnmanagedType.SafeArray)

However this doesn't seem to be working, does anyone have any tips of how I could pass this as a parameter?

Here is my full c# source:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Reflection;

namespace ExpandExcel
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class ExpandExcelStandard
    {
        #region Public Static Methods

        [return: MarshalAs(UnmanagedType.SafeArray)]
        public static T[] RemoveDuplicates<T>([MarshalAs(UnmanagedType.SafeArray)] ref T[] arr)
        {
            // Creates a hash set based on arr
            HashSet<T> set = new HashSet<T>(arr);
            T[] resultArr = new T[set.Count];
            set.CopyTo(resultArr);
            return resultArr; // Return the resultArr
        }

        #endregion
    }
}

Here is my full VBA source:

Sub main()
    Dim arr(1000000) As Variant

    Dim ExpandExcel As ExpandExcelStandard
    Set ExpandExcel = New ExpandExcelStandard

    For i = 0 To UBound(arr)
        Randomize
        arr(i) = Int((1000000 + 1) * Rnd)
    Next i

    Dim resultArr() As Variant

    resultArr = ExpandExcel.RemoveDuplicates(arr)
End Sub
6
  • You need to show us the full C# declaration, and the full native definition (vba, other) Commented Mar 20, 2020 at 14:37
  • I mean't this as a general question, I was making a point of saying that marshalling it as a safe array wouldn't work. I want people to give me tips on how they think they could tackle this. Commented Mar 20, 2020 at 15:11
  • It's very possible that you don't even need a specific MarshalAs. p/invoke offers lots of possibilities, it really depends on the two sides of the interop boundary. Provide code if you need help Commented Mar 20, 2020 at 15:23
  • I have edited the original question to include the source code :) Commented Mar 20, 2020 at 15:29
  • 1
    Surely the real problem is that you can call this method at all. Neither generic nor static methods are [ComVisible]. To match the VBA code it will have to be public object[] RemoveDuplicates(ref object[] arr). How you are going to define equality for these objects is a mystery btw. Commented Mar 20, 2020 at 15:55

1 Answer 1

2

You can't use generics with COM, you can't use static functions, etc. Here is a similar code that should work:

VB

Sub main()
    Dim arr(1000000) As Variant

    For i = 0 To UBound(arr)
        Randomize
        arr(i) = Int((1000000 + 1) * Rnd)
    Next i

    Set ExpandExcel = CreateObject("ExpandExcelStandard") // I used late binding but early is fine too
    resultArr = ExpandExcel.RemoveDuplicates(arr)
End Sub

C#

[ProgId("ExpandExcelStandard")] // because I wanted late binding, I declared a progid
[ComVisible(true)]
public class ExpandExcelStandard
{
    // .NET object (w/o any Marshal spec) is passed as an automation Variant
    public object[] RemoveDuplicates(object[] arr) => new HashSet<object>(arr).ToArray();
}
Sign up to request clarification or add additional context in comments.

3 Comments

Didn't work, gave the error, "Method or data member not found".
@user3551497 - are you sure you have copied my code 100% exactly? I've tested it.
Adding ref before object[] worked for me, thanks a lot for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.