I want to call a series of C++ methods, typically with the output of one C++ method being the input to the next. For performance reasons, I do not want to marshal the data back and forth on every call but instead keep all the memory in unmanaged space - these are really large arrays. Now the obvious answer is: write one method in C++ that calls all the methods. However, I want more control from the C#/managed side - sometimes saving intermediate results.
I wrote an UmanagedArray class that inherits from SafeHandle. I have a protected IntPtr called 'UnmanagedPtr'. I added a float[] property which gets and sets an array of float data, which I would use only to get data into unmanaged memory and extract it out, as such:
// float* AllocateAndFillArray(float* data, int length)
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr AllocateAndFillArray(float[] data, int length);
// void CopyUnmanagedToManaged(float * data, float *result, int length)
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
private static extern void CopyUnmanagedToManaged(IntPtr input, float[] result, int length);
// void FreeArray(void * array)
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
private static extern void FreeArray(IntPtr data);...
public float[] Data { get { if (UnmanagedPtr == IntPtr.Zero) { return new float[0]; } float[] result = new float[Length]; CopyUnmanagedToManaged(UnmanagedPtr, result, Length * sizeof(float)); return result; } set { if (UnmanagedPtr != IntPtr.Zero) { FreeArray(UnmanagedPtr); UnmanagedPtr = IntPtr.Zero; Length = 0; } if ((value != null) && (value.Length > 0)) { UnmanagedPtr = AllocateAndFillArray(value, value.Length * sizeof(float)); Length = value.Length; } } }
The C++ code:
extern "C" __declspec(dllexport) void FreeArray(void * array) { free(array); } extern "C" __declspec(dllexport) void* AllocateAndFillArray(void* data, size_t length) { void *memptr = (float*)malloc(length * sizeof(float)); memcpy(memptr, data, length); return memptr; } extern "C" __declspec(dllexport) void CopyUnmanagedToManaged(void* data, void* result, size_t length) { memcpy(result, data, length); }
This works fine. My issue is this: I want to make a generic UnmanagedArray<T>{} class that can manage arrays (1-D and 2-D) of any value type - int, long, float, double for starters. Is there any way to do this? Using void* in the C++ side works fine when declared in C# as float[]. I can't figure out how to overload the DLLImport to accommodate any type.