2

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?

  • Does this answer your question? [std::string in C#?](https://stackoverflow.com/questions/874551/stdstring-in-c) – shingo Aug 09 '23 at 14:59

0 Answers0