Как отправить указатель (указывающий на doubleArray) из кода C ++ в код C # с помощью DllImport (и из C # в C ++)? - PullRequest
0 голосов
/ 22 марта 2012

Итак, дело в том, что у меня есть массив double, который я хотел бы отправить в мое приложение C # через работающую C ++ DLL (загруженную моим приложением C #).

Кажется, я должен использовать IntPtr или что-то подобное для обмена массивами или строками (массивом символов), но я не могу понять, как это сделать ...

Кто-нибудь может сказать (+ пример), как отправить "double []" или "строку" в / из кода C # / C ++?

Вот пример кода:

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;
}

С этим кодом я получаю следующую ошибку ::

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

1 Ответ

0 голосов
/ 11 июля 2012

Проблема в том, что когда вы вызываете ваш обратный вызов из DLL C ++, nbArr указывает на первое значение в массиве значений типа double, созданном в собственном коде.Лучший способ - выполнить маршалирование в нативный код и из него, чтобы получить желаемый результат.

Чтобы упорядочить эти данные, вы должны передать массив как тип IntPtr, а не тип double [].Вам также необходимо передать количество элементов в массиве.Таким образом, мы имеем дело с указателями, которые можно маршалировать.

Вот завершенный код:

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;
    }

Вы также захотите освободить динамическую память, созданную вами в собственном коде C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...