Pointer (array of int) from C++ to C#

rhino5

#1

Hi,

I am learning Rhino plugin development when wrapping C++ classes to pass data to C#.

I have question about pointers.

In C++ I have a class that has a getter of “int* values”, which is just array of integers.
I class works and I can return integer one by one from class, but do not know how to pass whole array.
But every array in C++ is a pointer. So how to return values associated with a pointer (array of integers) to C#?

I tried this when passing C++ function to C#, but ok pointers do not exist in C# and I wonder if int* is correct:

SAMPLELIBRARY_C_FUNCTION int* colors(int x) {
	MyGraph g(x);
	g.addEdge(0, 1);
	g.addEdge(0, 2);
	g.addEdge(1, 2);
	g.addEdge(1, 3);
	g.addEdge(2, 3);
	g.addEdge(3, 4);
	g.greedyColoring();
	return g.getValues();
}

What is a correct way to pass int* colors function in C# in UnsafeNativeMethods.cs to get integer array?
For now I tried:

[DllImport(Import.lib, CallingConvention = CallingConvention.Cdecl)] internal static extern int[] colors(int x);

and then I print array values:
int[] values = UnsafeNativeMethods.colors(5); for(int i = 0; i < values.Length; i++) Rhino.RhinoApp.WriteLine(values[i].ToString());

But try catch block gives me an exception in Rhino:
Cannot marshal ‘return value’: Invalid managed/unmanaged type combination.


(Dale Fugier) #2

Passing arrays back and fourth can be a bit of a challenge.

If you Google “PInvoke Array” you will find numerous suggestions.

The Rhino C++ SDK contains a template array class, and RhinoCommon has interop wrappers for the most popular variations of these. So if I were trying to call a Rhino C++ SDK function that returned an array of ints, I might write my C# wrapper like this:

public int[] GetIntValues()
{
  using (var arr = new SimpleArrayInt())
  {
    var ptr_array = arr.NonConstPointer();
    var count = UnsafeNativeMethods.GetIntValues(ptr_array);
    if (count > 0)
      return arr.ToArray();
    return new int[0];
  }
}

where SimpleArrayInt can be found in the Rhino.Runtime.InteropWrappers namespace.

My “C” code could then look like this:

RH_C_FUNCTION int GetIntValues(ON_SimpleArray<int>* pIntArray)
{
  int rc = 0;
  if (0 != pIntArray)
  {
    pIntArray->Append(1);
    pIntArray->Append(2);
    pIntArray->Append(3);
    // etc...
    rc = pIntArray->Count();
  }
  return rc;
}

Perhaps this helps?

– Dale


#3

Thank you for an answer.

Now I am trying to replicate your code within my case.

First question as I started from C++, where can I find ON_SimpleArray ?
Now I probably have to understand how to reference Rhino in C++. Any reference?

Also I have declared an array inside class and I have a getter function inside C++ class. I was thought that pointer would be deleted after I called function. Hmm


#4

I found by search “PInvoke Array” this bit which works fine. Tested and ran it on Rhino.
Now I am wondering how to get inside a class and get an array from it.
Ech… Now I see that when I try to get pointer from a class I get random number. No errors. But no result.

program.cs (C#)

static class CPPDLL
    {
        [DllImport(“ExternalLibrary.dll”)]
        private static extern IntPtr ReturnIntArray();
        public static int[] ReturnIntArray(int length)
        {
            int[] ReturnArray = new int[length];
            Marshal.Copy(ReturnIntArray(), ReturnArray, 0, length);
            return ReturnArray;
        }
}

The corresponding C++ code is as follows:

main.cpp (C++)

int* ReturnIntArray()
{
    static int myArray[5] = {1, 2, 3, 4, 5};
    return myArray;
}

main.h (C++)

extern “C”
{
    int* ReturnIntArray();
}

#5

Heh, when I tried to write something like this I get no errors but random numbers:
int array[5] = myClass.GetValues();

But when I write this thing it works and I get correct values, but I have a feeling there is a better way to do this rather than copying values to new empty array instead of passing whole pointer:

SAMPLELIBRARY_C_FUNCTION int* ReturnIntArray() {
	MyGraph g(5);
	g.addEdge(0, 1);
	g.addEdge(0, 2);
	g.addEdge(1, 2);
	g.addEdge(1, 3);
	g.addEdge(2, 3);
	g.addEdge(3, 4);
	g.greedyColoring();
	static int myArray[5];
	for (int i = 0; i < 5; i++) {
		myArray[i] = *(g.getValues() + i);
	}
	return myArray;
}

#6

In this case of copying values to new array I have to deal with memory.

How to delete the array after I copy it to C# array?


(Dale Fugier) #7

Hi Petras,

Can I assume you are not a C++ programmer? Can I also assume you’ve got some kind of C++ library that you want to access from C#? Perhaps you can tell us more about what you are trying to do and why?

– Dale