I'm working on a C# application that requires some data processing to be done in a dll. Im in the process of setting up the dll and making sure that I can pass values back and forth before dropping in the c++ scripts that I wrote. I am passing in a struct containing my input parameters, that I would like to be modified in the dll, and I have some test code to modify these parameters, but the values are not being changed after the external method is called.
Here is the method in dllmain.cpp
:
struct InputParams
{
std::string inFile;
int xSize;
int ySize;
int zSize;
char axis;
int** grid;
};
#define EXPORTED_METHOD extern "C" __declspec(dllexport)
EXPORTED_METHOD
BOOL objectToTopo(InputParams* in) {
int val = 1;
// Allocate memory for rows
int** pArray = static_cast<int**>(LocalAlloc(LMEM_FIXED, in->xSize * sizeof(int*)));
if (!pArray)
return false;
// Allocate memory for cols
for (int i = 0; i < in->xSize; i++)
{
pArray[i] = static_cast<int*>(LocalAlloc(LMEM_FIXED, in->ySize * sizeof(int)));
if (!pArray[i])
return false;
}
// Fill 2d array with values
for (int r = 0; r < in->xSize; r++)
for (int j = 0; j < in->ySize; j++)
pArray[r][j] = val++;
in->grid = pArray;
return true;
}
And here is the corresponding C# to call this:
[StructLayout(LayoutKind.Sequential)]
public struct InputParams
{
public string? inFile;
public int xSize;
public int ySize;
public int zSize;
public char axis;
public IntPtr grid;
};
public class ObjectToTopoServiceFacade : IObjectToTopoServiceFacade
{
public ObjectToTopoServiceFacade() { }
public TopoDTO GetTopo()
{
InputParams inputParams = new InputParams();
inputParams.xSize = 5;
//inputParams.ySize = 5;
var result = objectToTopo(ref inputParams);
if (result)
{
int[][] gridOut = new int[inputParams.xSize][];
for (int i = 0; i < inputParams.xSize; i++)
gridOut[i] = new int[inputParams.ySize];
IntPtr[] ptrRows = new IntPtr[inputParams.xSize];
Marshal.Copy(inputParams.grid, ptrRows, 0, inputParams.xSize);
for (int i = 0; i < inputParams.xSize; i++)
Marshal.Copy(ptrRows[i], gridOut[i], 0, inputParams.ySize);
for (int j = 0; j < inputParams.xSize; j++)
Console.WriteLine(gridOut[j]);
Console.WriteLine(inputParams.ySize);
}
return new TopoDTO();
}
[DllImport(@"[Path to dll file]", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern bool objectToTopo(ref InputParams inputParams);
}
The specific error that I'm getting occurs on the first Marshal.copy()
call: System.ArgumentNullException: 'Value cannot be null. (Parameter 'source')'
To me this looks like the dll is not properly reassigning in->grid
. Perhaps my input parameters are not being passed by reference?