c # Wrapper в собственный код C ++, заключающий в себе параметр, который является указателем на массив - PullRequest
1 голос
/ 26 апреля 2010

У меня есть следующая простая DLL в неуправляемом коде c ++;

extern "C" __declspec(dllexport) void ArrayMultiplier(float (*pointerArray)[3], int scalar, int length); 

void ArrayMultiplier(float (*pointerArray)[3], int scalar, int length) 
{
    for (int i = 0 ; i < length ; length++)
    {
        for (int j = 0; j < 3; j++)
        { 
            pointerArray[i][j] = pointerArray[i][j] * scalar;
        }
    }
}

Я попытался написать следующую функцию-обертку для вышеупомянутого в c #:

    [DllImport("sample.dll")]
public static extern void ArrayMultiplier(ref float elements, int scalar, int length);

где элементы - это двумерный массив 3х3:

public float[][] elements = 
        {
            new float[]  {2,5,3},
            new float []  {4,8,6},
            new float []  {5,28,3}
        };

Приведенный выше код компилируется, но программа вылетает при вызове функции-оболочки:

Wrapper.ArrayMultiplier(ref elements, scalar, length);

Пожалуйста, помогите мне здесь и расскажите, что не так с приведенным выше кодом, или как можно написать обертку для простой функции c ++:

void SimpleFunction(float (*pointerToArray)[3]);

Спасибо всем заранее

1 Ответ

1 голос
/ 26 апреля 2010

Есть несколько способов сделать это.

Небезопасный маршрут, который хорошо работает с 2D-массивами (которые у вас есть):

    [DllImport("fastprocessing.dll", EntryPoint = "MyFunc")]
    public static extern void MyFuncViaDLL(int inPtr, int outPtr, int inSize1, int size2, int param);

вызывается через

    private unsafe float[] MyFunc(float[] inData, int inSize1, int inSize2, int param1, int param2) {
        float[] theOutData = new float[inChannelData.Length];
        fixed (float* inBufferPtr = &inChannelData[0]) {
            fixed (float* outBufferPtr = &theOutData[0]) {
                MyFuncViaDLL((int)inBufferPtr, (int)outBufferPtr, inSize1, inSize2, param);
            }
        }
        return theOutData;
    }

Это будет работать небезопасным способом, но вам нужно будет изменить входные массивы на одномерные. Я думаю, что в любом случае это лучшая идея, но я думаю, что именно так.

Если вы хотите быть в безопасности, добавьте еще один параметр, равный размеру самого массива, а затем выполните некоторую сортировку. Опять же, вам нужно перейти в одномерные массивы:

Вместо этого вы хотите выполнить сортировку, например:

    [DllImport("fastprocessing.dll", EntryPoint = "MyFunc")]
    public static extern void MyFuncViaDLL([MarshalAs(UnmanagedType.LPArray)]float[] inPtr, int size1, int size2, int totalSize, int param2);

Тогда просто вызовите функцию напрямую:

    MyFuncViaDLL(array, size1, size2, size1*size2, param1, param2);

Ваш C ++ изменится на:

void ArrayMultiplier(float *pointerArray, int inSize1, int inSize2, int inTotalSize, int scalar) 
{
    int i, j, index;
    for (i = 0 ; i < size1; i++)//note that length++ would be very very wrong here
    {
        for (j = 0; j < size2; j++)
        { 
            index = i*size2 + j;
            if(index >= inTotalSize) { return; } //avoid walking off the end
            pointerArray[i*size2 +  j] *= scalar;
        }
    }
}

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

Сделав все этого, я должен спросить - почему бы просто не сделать это непосредственно в C # и не избавить себя от хлопот служб взаимодействия, таких как сортировка? C ++ имеет тенденцию быть быстрее для сложных вещей, но для быстрого обхода массива я видел, как C # ведет себя довольно хорошо. Это может быть довольно быстро и в C #, если это одномерный массив:

 int i;
 for (i = 0; i < array.length; i++){
    array[i] *= scalar;
 }
...