using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using ReturnCPPArrayToCSharpExample_CSharpSide_;
namespace DLLCall
{
class Program
{
[DllImport("E:\\C++Projects\\ReturnC++ArrayToDLLExample(1D)\\DLLFromCPPToCSharp\\Debug\\ArrayDLLFromCPPToCSharp")]
public static extern IntPtr[] convertMatrix(int height, int width, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(JaggedArrayMarshaler))]byte[][] inputArr);
[DllImport("E:\\C++Projects\\ReturnC++ArrayToDLLExample(1D)\\DLLFromCPPToCSharp\\Debug\\ArrayDLLFromCPPToCSharp", CallingConvention = CallingConvention.Cdecl)]
public static extern int ReleaseMemory(IntPtr ptr);
static void Main(string[] args)
{
int height = 3;
int width = 3;
byte[][] inputArr = new byte[3][];
inputArr[0] = new byte[] { 1, 1, 1 };
inputArr[1] = new byte[] { 1, 1, 1 };
inputArr[2] = new byte[] { 1, 1, 1 };
IntPtr[] obj = new IntPtr[3];
obj = convertMatrix(height, width, inputArr);
IntPtr[] outputMatrixOfPointers = new IntPtr[3];
byte[,] result = new byte[3, 3];
for (int i = 0; i < result.Length; i++)
{
}
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ReturnCPPArrayToCSharpExample_CSharpSide_
{
class JaggedArrayMarshaler : ICustomMarshaler
{
static ICustomMarshaler GetInstance(string cookie)
{
return new JaggedArrayMarshaler();
}
GCHandle[] handles;
GCHandle buffer;
Array[] array;
public void CleanUpManagedData(object ManagedObj)
{
}
public void CleanUpNativeData(IntPtr pNativeData)
{
buffer.Free();
foreach (GCHandle handle in handles)
{
handle.Free();
}
}
public int GetNativeDataSize()
{
return 4;
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
array = (Array[])ManagedObj;
handles = new GCHandle[array.Length];
for (int i = 0; i < array.Length; i++)
{
handles[i] = GCHandle.Alloc(array[i], GCHandleType.Pinned);
}
IntPtr[] pointers = new IntPtr[handles.Length];
for (int i = 0; i < handles.Length; i++)
{
pointers[i] = handles[i].AddrOfPinnedObject();
}
buffer = GCHandle.Alloc(pointers, GCHandleType.Pinned);
return buffer.AddrOfPinnedObject();
}
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return array;
}
}
#include <iostream>
using namespace std;
using byte = unsigned char;
extern "C" __declspec(dllexport) unsigned char** convertMatrix(int height, int width, byte inputArr[][3])
{
byte** arr = 0;
arr = new byte*[height];
for (int i = 0; i < height; i++)
{
arr[i] = new byte[width];
for (int j = 0; j < width; j++)
{
arr[i][j] = 0;
}
}
return arr;
}
extern "C" __declspec(dllexport) int ReleaseMemory(int* pArray)
{
delete[] pArray;
return 0;
}
What I have tried:
What I have tried:
-I'm not sure about this myself, but based on what I have read, IntPtr[] can be used to invoke methods even if the method return type is different as it could hold different objects, so I felt that should'nt be an issue.
-Add in a custom class to marshal 2D-arrays as given from codeproject as (a.k.a JagggedArrayMarshaller) as I could understand that normal marshaling methods could only cater to a 2D array.
-However there were issues when I tried to invoke the method but I do not understand why the marshalling to unmanaged code to managed does not work:
IntPtr[] obj = new IntPtr[3];
obj = convertMatrix(height, width, inputArr);
As a result, it returns the error:
An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in ReturnCPPArrayToCSharpExample(CSharpSide).exe
Additional information: Cannot marshal 'return value': Invalid managed/unmanaged type combination.