Search code examples
c#arraysinteroppinvoke

Converting data from C++ dll in C#


I use C# and C++ dll. I want to send array from C++ to C#. I want to return from C++ array with 512 doubles. In C++ code it works perfect. I have results exactly what I expected in array of double.

Later I send data from C++ to C# and convert this data to array of double in C#. First 450 elements from C++ are moved to array in C# without any error. But left doubles are weird and they don't have anything common with input data.

I don't know why exactly at 450 element starts wronge doubles until end.

EDIT. Also the same issue when I change arrays in C++ and C# to float and also when I parse data to integer.

C# code.

[DllImport(@"C:\Users\Jaryn\Documents\Visual Studio 2013\Projects\MathFuncDll\Debug\MathFuncDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr One(string address);

static void Main(string[] args)
{
    var pointer = One(@"C:\Users\Jaryn\Documents\101_ObjectCategories\accordion\image_0002.jpg");
    var result = new double[512];
    Marshal.Copy(pointer, result, 0, 512);
    foreach (var x in result)
    {
        Console.WriteLine(x + " ");
    }
}

MathFuncsDll.h

#include <stdexcept>
using namespace std;

namespace MathFuncs
{
    extern "C" { __declspec(dllexport) double* One(char* str); }
}

MathFuncsDll.cpp

double* One(char* adress)
{

    IplImage* img = cvLoadImage(adress, CV_LOAD_IMAGE_COLOR);

    double data[512];
    int iteration = 0;

    ...     

    for (int h = 0; h <h_bins; h++)
    {
        for (int s = 0; s < s_bins; s++)
        {
            double bin_value = 0;
            for (int v = 0; v < h_bins; v++)
            {
                bin_value += cvGetReal3D(hist->bins, h, s, v);
                data[iteration] = bin_value;
                iteration++;
            }
        }
    }

    ...


    return data;
}

Solution

  • Your problem is that you are returning the address of a local variable. As soon as the function returns, that local variable's life ends. And so the address you return is the address of an object whose life is over.

    The clean way to do this is to let the caller allocate the array and have the callee populate it. Have the caller pass the address of the first element of the array, and the length of the array. Then the callee can be sure not to write beyond the end of the array.