Sending a 2D int array between C# and C++ - c#

I'm trying to create a solution where I can run a 2D int array within a C# program through CUDA, so the approach I'm currently taking to try and do this is by creating a C++ dll which can handle the CUDA code then return the 2D array. The code I'm using to send my array to the dll and back again is below.
#include "CudaDLL.h"
#include <stdexcept>
int** cudaArrayData;
void CudaDLL::InitialiseArray(int arrayRows, int arrayCols, int** arrayData)
{
cudaArrayData = new int*[arrayCols];
for(int i = 0; i < arrayCols; i++)
{
cudaArrayData[i] = new int[arrayRows];
}
cudaArrayData = arrayData;
}
int** CudaDLL::ReturnArray()
{
return cudaArrayData;
}
The problem however is I get an error in C# on the return, "Cannot marshal 'return value': Invalid managed/unmanaged type combination." My hope was if I returned the array back as a pointer C# might have hopefully understood and accepted it however no such luck.
Any idea's?

As you’re using int[,] in C#, int** is not the right corresponding type in C++. int[][] is an array of arrays of ints, similar to int** in C++; whereas int[,] is one array of ints with 2D indexing: index = x + y * width. Using int** in C#/C++ interop is difficult, as you have many pointers to either managed or unmanaged memory, which is not directly accessible from one to another (see further down).
Already in InitialiseArray(..., int** arrayData) you read somewhere in your memory but not in array values as you don't pass an array with pointers to arrays of ints, you pass one single array of int.
When you return int** in ReturnArray(), your problem is that .net has no clue how to interpret that pointer to an pointer.
To fix this, use only int* on C++ side and don’t return the array as a function return value, this would only give you a pointer to the unmanaged array and not the entire data in managed memory. It is possible to use this from C#, but probably not in the way you intend to do. Use an array allocated in C# as function argument in void ReturnArray(int* retValues) to copy the data to.
The other problem is then data copying and memory allocations. You can avoid all of these steps if you handle memory in C# right, i.e. forbid the garbage collector to move your data around (it does that when cleaning up unused objects). Either use a fixed{} statement or do it manually via GCHandle.Alloc(array, GCHandleType.Pinned). Doing so, you can directly use the C# allocated arrays from within C++.
Finally, if all you need is to let a CUDA kernel run on your C# data, have a look at some cuda wrappers that handle all the Pinvoke hazards for you. Like managedCuda (I maintain this project) or cudafy and some others.

Related

Storing data for unmanaged code when using P/Invoke

I have an array of arrays of this struct (shown here in C#, but existing in C++ as well):
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
IntPtr name; //pointer to string, char* on C++ side
long pValues;
long jValues;
long eValues;
long kValues;
int cost;
};
and an algorithm in a C++ DLL that does work on it, being called from managed C# code. It's CPU-heavy, which is what necessitates this as it runs much faster in C++ than C#. The managed (C#) side never has to know the contents of the struct data, as the algorithm only returns a single array of ints.
So, how would I go about storing this data in the most efficient way (ie with the least overhead), for the lifetime of the application? I think I have it narrowed down to two options:
Initialize structs and set values in C#, pin memory with GCHandle and pass reference to C++ whenever I want to do work (see this post on Unity forums)
Initialize structs and set values in C++, have structs persist in memory on unmanaged side
So my questions are very specific:
With 1, I'm confused as to how marshalling works. It looks like in MSDN: Copying and Pinning that you are able to pass arrays of structures by pinning and passing a reference to the pinned data, without having to copy or convert any of it (and as long as the struct looks the same on both sides). Am I reading that correctly, is that how it actually works? Referring to the Unity3d forum post, I see Marshal.PtrToStructure being called; I thought that performs copying operations? As the data would be stored on the managed side in this instance, having to copy and/or convert the data every time the C++ function is called would cause a lot of overhead, unless I'm thinking that those type of operations are a lot more expensive than they actually are.
With 2, I'm wondering if it's possible to have persistence between C++ calls. To the best of my knowledge, if you're P/Invoking from a DLL, you can't have persistent data on the unmanaged side, so I can't just define and store my struct arrays there, making the only data transferred between managed and unmanaged the int array resulting from the unmanaged algorithm. Is this correct?
Thank you very much for taking the time to read and help!
If the C# code does not need to know the internals of the array and the structure, don't expose it to the C# code. Do all the work on this type in the unmanaged code and avoid marshalling overhead.
Essentially, you want to follow this basic pattern. I'm sure the details will differ, but this should give you the basic concept.
C++
MyStruct* newArray(const int len)
{
return new MyStruct[len];
}
void workOnArray(MyStruct* array, const int len)
{
// do stuff with the array
}
void deleteArray(const MyStruct* array)
{
delete[] array;
}
C#
[DllImport(dllname)]
static extern IntPtr newArray(int len);
[DllImport(dllname)]
static extern void workOnArray(IntPtr array int len);
[DllImport(dllname)]
static extern void deleteArray(IntPtr array);

Most efficient way to pass data from C++ to C#

I am looking for the best way to transfer a large amount of data from C++ (struct or a value class?) into a C# class doing as little data copying as possible. In the sample code below, I have a vector of SubClass objects that has the potential to be very large (10+ million). So I want to avoid a data copy if possible.
Should I/can I just allocate the objects in GC first and use them directly in c++ and forget about the native c++ structures? (Performance is my concern with this one.)
Or, is there some trick that I leverage what is allocated in C++ without causing a data copy?
Here is a sample of something along the lines of what I want to use as a transfer between managed and unmanaged code.
#include <string>
#include <vector>
struct SubClass {
std::string DataItem1;
// lots more here
std::string DataItem50;
};
struct Sample {
int IntValue;
std::string StringValue;
std::vector<std::string> SmallList;
std::vector<SubClass> HugeList;
};
If I can avoid getting into the weeds with pinvoke and COM classes, I would prefer it.
Following the example from Unity (who uses C#), Native plugin example uses a GC handle to transfer data from C# to C++. We can try the opposite to send data to C++ from C#.
Pin down a C# variable to allow faster copying.
using System;
using System.Collections;
using System.Runtime.InteropServices;
// vertices is a Vector3[], where Vector3 is a struct
// of 3 floats using a sequential layout attribute
void test(){
GCHandle gcVertices = GCHandle.Alloc (vertices, GCHandleType.Pinned);
}
Transfer the handle to C++ using marshaling. It's unavoidable that you have to copy something. Here copying a pointer should be good enough. More on marshaling according to Microsoft doc.
[DllImport("your dll")]
private static extern void SendHandle(IntPtr vertexHandle, int vertexCount);
SendHandle(gcVertices, vertices.Length);
Inside C++, you'll receive the handle as a pointer type to a C++ type of your choosing. In this case, vertices are a list of structs of 3 floats. The reference code decided to use float *. You just need to do pointer arithmetic properly depending on the pointed type, including the case of void *.
extern "C" __decl(dllexport) void SendHandle(float* vertices, int vertexCount);
Here the example code copies data directly from the pointer, but you can also write to the pointer's location.
for (int i = 0 ; i < vertexCount; i++)
{
// read from C# heap
float x = vertices[0];
float y = vertices[1];
float z = vertices[2];
// write to C# heap
*vertices = sqrt(x);
*(vertices + 1) = sqrt(y);
*(vertices + 2) = sqrt(z);
vertices += 3; // because it is a list of struct of 3 floats
}
Clean up the pinned handle from the C# side to resume the garbage collector.
gcVertices.Free();
As for strings, I believe the interop library has an implementation that handles pointer arithmetic and copying for you. You could probably just use a string type directly inside the exposed export function, as long as you specify how to marshal it with the MarshalAs attribute in C# and a library in C++ if you are not converting to the C type char *.

How to cast an allocated memory block to an array addressable data type.

I am trying to Marshal some data from c# to a c library. The struct that I need to pass is just a collection of pointers... something like:
struct sometype {
type1* element1;
type2** element2;
type3** element3;
type4* element4;
}
Now... I've opted to forgo the attempt to copy all of these types into c# and marshal them as structures and decided to just fill a IntPtr array with the correct data in the correct order and pass it as a pointer. As you can see, in this setup I am passing a 4 position array of pointers with positions 1 and 2 being arrays of pointers themselves. It was simple enough and indeed does work when I marshal by fixing the IntPtr array...
fixed(IntPtr* ptr = structArray){
InteropCall(ptr);
}
However, I soon realized that the c library is actually keeping a reference to the struct and after sometime, expectedly breaks when the array is moved or collected. So my solution was to allocate a block of memory using Marshal.AllocHGlobal and hold on to the reference throughout the time the c library needs that data.
So I run this:
IntPtr* pointerArray = (IntPtr*)Marshal.AllocHGlobal (IntPtr.Size * 4);
However, pointerArray always comes out as IntPtr.Zero... or i guess... just zero.
What am I doing wrong? Can I not cast a memory block into a pointer datatype? What if I wanted a byte* or int* so that I can operate on the memory block like an array?

Marshal between C# byte array and C++ byte array

I have a C# array<System::Byte> and I want that to translate to a C++ byte*. How can I do that? I am using C++/CLR because it lets me use managed/unmanaged code in the same project. I'm basically writing a DLL and making a few methods that can be called via C#, but that contain unmanaged C++ code.
So basically, my C++/CLR method header is this:
void testMethod(array<Byte>^ bytesFromCSharp);
and inside of that testMethod I would like to translate the bytesFromCSharp into a byte* which can be used by other unmanaged C++ code. I malloced the byte* array and wrote a for loop to copy byte by byte but it feels like there should be a better solution.
edit: Example of Hans' technique from his answer below:
//C#
byte[] myBytes = {1,2,3,4};
//C++/CLI
void testMethod(array<byte>^ myBytes) {
pin_ptr<byte> thePtr = &myBytes[0];
byte* bPtr = thePtr;
nativeCode(bPtr);
...
}
Use the pin_ptr<> template class to pin the array and generate a pointer that native code can use. Pinning it ensures that the array cannot be moved by the garbage collector while the native code is using it.
Just make sure that the native code cannot use the array anymore after the pin_ptr<> variable goes out of scope. Which also means that native code storing the pointer for later use is not okay. If it does then you have to make a copy.

Passing a SAFEARRAY from C# to COM

I use 3rd party COM to find faces in a picture. One of the methods has the following signature, from SDK:
long FindMultipleFaces(
IUnknown* pIDibImage,
VARIANTARG* FacePositionArray
);
Parameters: pIDibImage[in] - The image
to search.
FacePositionArray[out]- The array of
FacePosition2 objects into which face
information is placed. This array is
in a safe array (VARIANT) of type
VT_UNKNOWN. The size of the array
dictates the maximum number of faces
for which to search.
which translates into the following C# method signature (from metadata):
int FindMultipleFaces(object pIDibImage, ref object pIFacePositions);
Being optimistic I call it the following way but get an exception that the memory is corrupt. The exception is thrown only when a face is present in the image.
FacePosition2[] facePositions = new FacePosition2[10];
object positions = facePositions;
int faceCount = FaceLocator.FindMultipleFaces(dibImage, ref positions);
What's the right way to pass SAFEARRAY to unmanaged code?
It's something like you initialize an array using Marshal.AllocCoTaskMem and then use Marshal.Copy to copy it to unmanaged memory and the pass an IntPtr pointing to the array into the COM method.
In general, look at the Marshal class:
http://msdn.microsoft.com/en-gb/library/system.runtime.interopservices.marshal.aspx
Oops, it seems it only needed from me to initialize the array because FacePosition2 was not a struct but class and it was not initialized automatically as I though it would. This piece was missing:
for (var i = 0; i < facePositions.Length; i++)
{
facePositions[i] = new FacePosition2();
}
There are more sophisticated method, but opinion is more correct:
change this signature Interop, so, he looks like taking an array.
Accessing a SafeArray Result from a COM Call in C#
Default Marshaling for Arrays
Correcting Common Interop Assembly Problems

Categories

Resources