C ++ DLL Взаимодействие с C #: Предоставление многомерных массивов неизвестного размера и управление памятью - PullRequest
2 голосов
/ 18 июня 2011

У меня есть библиотека C ++, которая занимается какой-то жесткой финансовой математикой (Quantlib).У меня есть обычная DLL-библиотека C ++, построенная на ее основе, которая предоставляет облегченный интерфейс к внешнему приложению C #, чтобы позволить пользователям передавать различные параметры, запускать сценарии и т. Д. Затем DLL возвращает данные для отображения.

Мне действительно неясно, как обращаться с интерфейсом между dll и слоем C #, и, в частности, я понятия не имею, где обрабатывается выделение / освобождение памяти, т.е. в C # или dll

По существуЯ бы хотел, чтобы моя dll возвращала класс или структуру, которая содержит двумерный массив значений (double, char * и т. Д.).Я не буду знать размер этого массива в то время, когда я вызываю dll, так что он должен быть распределен самой dll, я думаю.

В данный момент ячтобы dll возвращала значение looooooooong char * со списком значений, разделенных каналом.Кажется, это работает, но это не кажется мне особенно элегантным решением.

Любая помощь, ребята?

РЕДАКТИРОВАТЬ

спасибомного за все ваши отзывы.Извините, я не занимался программированием на DLL годами, поэтому был немного глупый вопрос.

Я решил просто рассматривать 2d-массив как 1d-массив со смещением высоты / ширины на стороне C ++, ипросто жить с угадыванием размера массива заранее.Создание 2d-массива на стороне C # и сортировка его в C ++ таким образом, кажется, работает нормально.

Вот что у меня есть.Мысли, кто-нибудь?

C #:

    [DllImport(<dllPath>, CallingConvention = CallingConvention.Cdecl)]
    static extern void ChangeArray2d(double[,] arr, int l1, int l2);

    //populated with some sample values
    double[,] arr = new double[,] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 } };
    ChangeArray2d(arr, arr.GetLength(0), arr.GetLength(1));

C ++:

 __declspec(dllexport) void ChangeArray2d( double* arrayin, int height, int width)
{
    for (int n = 0; n<height; n++){
        for (int m = 0; m<width; m++){
            arrayin[n*width+m]  = arrayin[n*width+m] + 100;
        }
    };
    return;
}

1 Ответ

2 голосов
/ 18 июня 2011

Как правило, это обычный шаблон для выделения буфера, передачи его (с размером буфера в качестве максимального объема данных, который вы можете обработать за один раз) в собственную функцию C ++, которая заполнит его, а затем для обработки данных / свободного буфера. Или повторно использовать буфер.

Если ваша нативная функция выделяет для вас буфер, и вы должны впоследствии его освободить - это очень хрупкий контракт, а также запрещает повторное использование памяти. Например. если вам нужно вызвать эту функцию 20 раз - у вас будет 20 ненужных выделений.

Примерно так:

private int YourNativeFunctionStub(IntPtr buffer, int bufferSize)
{
    int writtenToBufferBytes = bufferSize; // if it wrote less to buffer - it should return correct count of bytes
    // here your library fills the buffer with data
    return writtenToBufferBytes;
}

private double[] GetArrayFromNative()
{
    int bufsize = 1024; // probably you should find it by calling another func from your library?

    IntPtr nativeBuffer = Marshal.AllocHGlobal(bufsize);
    try
    {
        int bytesReceivedInBuffer = YourNativeFunctionStub(nativeBuffer, bufsize);

        int receivedArrayLength = bytesReceivedInBuffer / sizeof(double);
        var managedArray = new double[receivedArrayLength];
        Marshal.Copy(nativeBuffer, managedArray, 0, receivedArrayLength);
        return managedArray;
    }
    finally
    {
        Marshal.FreeHGlobal(nativeBuffer);
    }
}

UPD : см. Комментарий Ганса.

...