The following sample code demonstrates how an unmanaged C++ dll might create a 2D array of int values . The pointer to the array is returned in a structure that also contains the number of rows and columns. For demonstration purposes, unmanaged memory is allocated using LocalAlloc so that the allocations can be freed by managed code.
C++ dll code -
struct Test2DArray
{
int** p2D;
int nRows;
int nCols;
};
constexpr int ROWS = 2;
constexpr int COLS = 10;
// Unmanaged memory allocated with LocalAlloc so it can be freed in managed code with Marshal.FeeHGlobal
// Return FALSE if any memory allocation fails, LocalAlloc sets Win32 extended error code on failure
extern "C" __declspec(dllexport) BOOL Create2DIntArray(Test2DArray* pStruct)
{
int iValue{ 1 };
// Allocate memory for rows
int** pArray_ = static_cast<int**>(LocalAlloc(LMEM_FIXED, ROWS * sizeof(int*)));
if (!pArray_)
return FALSE;
// Allocate memory for columns
for (int i = 0; i < ROWS; i++)
{
pArray_[i] = static_cast<int*>(LocalAlloc(LMEM_FIXED, COLS * sizeof(int)));
if (!pArray_[i])
return FALSE;
}
// Fill 2d array with values
for (int r = 0; r < ROWS; r++)
for (int c = 0; c < COLS; c++)
pArray_[r][c] = iValue++;
pStruct->p2D = pArray_;
pStruct->nRows = ROWS;
pStruct->nCols = COLS;
return TRUE;
}
Sample C# console application to read the 2D array and print the values -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace CSconsoleApp
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct Test2DArray
{
public IntPtr p2D;
public int nRows;
public int nCols;
};
[DllImport("Array2D.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool Create2DIntArray(ref Test2DArray astruct);
static void Main(string[] args)
{
Test2DArray s = new Test2DArray();
var result = Create2DIntArray(ref s);
if(result)
{
int[][] int2DArray = new int[s.nRows][];
for (int i = 0; i < s.nRows; i++)
int2DArray[i] = new int[s.nCols];
IntPtr[] ptrRows = new IntPtr[s.nRows];
Marshal.Copy(s.p2D, ptrRows, 0, s.nRows);
for (int i = 0; i < s.nRows; i++)
Marshal.Copy(ptrRows[i], int2DArray[i], 0, s.nCols);
for (int r = 0; r < s.nRows; r++)
for (int c = 0; c < s.nCols; c++)
Console.WriteLine("int2DArray[{0}][{1}] = {2}", r, c, int2DArray[r][c]);
// Free unmanaged memory allocated for columns
for (int r = 0; r < s.nRows; r++)
Marshal.FreeHGlobal(ptrRows[r]);
// Free unmanaged memory allocated for rows
Marshal.FreeHGlobal(s.p2D);
}
}
}
}