I think I’m close and I bet the solution is something stupid.
I have a C++ native DLL where I define the following function:
DllExport bool __stdcall Open(const char* filePath, int *numFrames, void** data);
{
//creates the list of arrays here... don't worry, lifetime is managed somewhere else
//foreach item of the list:
{
BYTE* pByte = GetArray(i);
//here's where my problem lives
*(data + i * sizeofarray) = pByte;
}
*numFrames = total number of items in the list
return true;
}
Basically, given a file path, this function creates a list of byte arrays (BYTE*) and should return a list of pointers via the data param. Each pointing to a different byte array.
I want to pass an array of IntPtr from C# and be able to marshal each individual array in order. Here’s the code I’m using:
[DllImport("mydll.dll",EntryPoint = "Open")]
private static extern bool MyOpen(
string filePath, out int numFrames, out IntPtr[] ptr);
internal static bool Open(
string filePath, out int numFrames, out Bitmap[] images)
{
var ptrList = new IntPtr[512];
MyOpen(filePath, out numFrames, out ptrList);
images = new Bitmap[numFrames];
var len = 100; //for sake of simplicity
for (int i=0; i<numFrames;i++)
{
var buffer = new byte[len];
Marshal.Copy(ptrList[i], buffer, 0, len);
images[i] = CreateBitmapFromBuffer(buffer, height, width);
}
return true;
}
Problem is in my C++ code. When I assign *(data + i * sizeofarray) = pByte; it corrupts the array of pointers… what am I doing wrong?
UPDATE:
Just started to create a new solution to isolate concepts and already found something very weird. Take a look:
C# code
class Program
{
[DllImport("ArrayProvider.dll")]
private static extern bool Open(out int n, ref IntPtr[] ptr);
static void Main(string[] args)
{
int n;
var pList = new IntPtr[10];
Program.Open(out n, ref pList);
foreach (var p in pList)
{
Debug.WriteLine(p.ToInt32().ToString("X"));
}
}
}
C++ code
#include "stdafx.h"
#define DllExport __declspec( dllexport )
extern "C" {
DllExport bool __stdcall Open(int *n, void** data)
{
return true;
}
}
Before the call to native code, pList has 10 IntPtr.Zero elements. After returning from native call, it has only one… something wrong… and it also happens if I replace void** by BYTE**
The runtime will have no clue to the length of the array when receiving unmanaged arrays, you need to use the MarshalAsAttribute in conjunction with the SizeParamIndex field to specify the length of the array. There’s an example of this here.
You also don’t need to define the method signature as ref IntPtr[] for the array, use the InAttribute and OutAttribute.
E.x.: