0

So, the thing is that I have an array of double that I'd like to send to my C# application through a running C++ DLL (loaded by my C# app).

It seems that I should be using IntPtr or something like this to exchange arrays or string (array of chars) but I can't really figure out how to perfom it ...

Anyone could tell (+ example) some way to send "double[]" or "string" to/from C#/C++ code ?

Here is some piece of code as an example :

C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FuncPtr([MarshalAs(UnmanagedType.LPArray)] ref double[] dblArr);
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern void callCSharpFunctionDblArr(IntPtr fctPointer);

public static void printInConsoleDblArr(ref double[] nbArr)
{
    Console.Write("value = ");
    for(int i=0; i<nbArr.Length; i++)
        Console.Write(nbArr[i] + "; ");
    Console.WriteLine();

    for (int i = 0; i < nbArr.Length; i++)
        nbArr[i] = nbArr[i] + 1;

    Console.Write("value = ");
    for (int i = 0; i < nbArr.Length; i++)
        Console.Write(nbArr[i] + "; ");
    Console.WriteLine();
}
static void Main(string[] args)
{        
    FuncPtr printInConsoleDblArrDelegate = 
        new FuncPtr(printInConsoleDblArr);

    IntPtr printInConsoleDblArrPtr = 
        Marshal.GetFunctionPointerForDelegate(printInConsoleDblArrDelegate);

    Console.WriteLine("Second time called from C++ using the call back !!!");
    callCSharpFunctionDblArr(printInConsoleDblArrPtr);

    Console.ReadLine();
}

C++

__declspec(dllexport) void callCSharpFunctionDblArr( void *fctPointer(double*&) )
{
    double* dbl = new double[5];

    for(int i=0; i<5; i++)
        dbl[i] = (0.5*i);

    for(int i=0; i<5; i++)
        std::cout << "Before :: dbl[" << i << "] = " << dbl[i] << std::endl;
    fctPointer(dbl);
    for(int i=0; i<5; i++)
        std::cout << "After :: dbl[" << i << "] = " << dbl[i] << std::endl;
}

With this code, I get the following error ::

An unhandled exception of type 'System.AccessViolationException' occurred in ConsoleApplication1.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Jsncrdnl
  • 3,005
  • 5
  • 28
  • 43

1 Answers1

0

The issue is that when you call your callback from the C++ dll, nbArr points to the first value in the array of doubles created in the native code. The best way is to marshal to and from native code to get the desired output.

To marshal this data, you must pass the array as an IntPtr type, not a double[] type. You also need to pass the number of elements in the array. This way we are dealing with pointers that can be marshaled.

Here is the completed code:

C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FuncPtr(ref IntPtr dblArr, int size);
[DllImport("test1dll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void callCSharpFunctionDblArr(IntPtr fctPointer);


public static void printInConsoleDblArr(ref IntPtr nbArr, int size)
{
    // Marshal native to managed
    double[] values = new double[size];
    Marshal.Copy(nbArr, values, 0, size);

    Console.Write("value = ");
    for (int i = 0; i < size; i++)
        Console.Write(values[i] + "; ");
    Console.WriteLine();

    for (int i = 0; i < size; i++)
        values[i] = values[i] + 1;

    Console.Write("value = ");
    for (int i = 0; i < size; i++)
        Console.Write(values[i] + "; ");
    Console.WriteLine();

    // Marshal managed to native
    Marshal.Copy(values, 0, nbArr, size);
}

static void Main(string[] args)
{
    FuncPtr printInConsoleDblArrDelegate =
        new FuncPtr(printInConsoleDblArr);

    IntPtr printInConsoleDblArrPtr =
        Marshal.GetFunctionPointerForDelegate(printInConsoleDblArrDelegate);

    Console.WriteLine("Second time called from C++ using the call back !!!");
    callCSharpFunctionDblArr(printInConsoleDblArrPtr);

    Console.ReadLine();
}

C++

__declspec(dllexport) void callCSharpFunctionDblArr( void *fctPointer(double*&, int size) )
    {
        double* dbl = new double[5];

        for(int i=0; i<5; i++)
            dbl[i] = (0.5*i);

        for(int i=0; i<5; i++)
            std::cout << "Before :: dbl[" << i << "] = " << dbl[i] << std::endl;
        fctPointer(dbl, 5);
        for(int i=0; i<5; i++)
            std::cout << "After :: dbl[" << i << "] = " << dbl[i] << std::endl;
    }

You will also want to free the dynamic memory you created in the C++ native code.

Bill Nelson
  • 333
  • 3
  • 4
  • You can with a lot of work since STL is a C++ construct and won't directly work with C#. See [Vector into from C++ to C#](http://stackoverflow.com/questions/2747586/how-can-i-marshall-a-vectorint-from-a-c-dll-to-a-c-sharp-application) for more info. – Bill Nelson Jul 11 '12 at 15:52