views:

179

answers:

1

Hi, I have the following simple DLL in c++ un-managed code;

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

I have tried writing the following wrapper function for the above in c#:

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

where elements is a 2 dimentional 3x3 array:

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

The code given above compiles, but the program crashes when the wrapper function is called:

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

Please help me here, and tell me whats wrong with the code above, or how a wrapper can be written for a simple c++ function:

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

Thank you all in advance

+1  A: 

There are a few ways to do this.

The unsafe route, which works well with 2D arrays (that you have):

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

called via

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

That will work in an unsafe way, but you'd need to change your input arrays into 1D arrays. I think that's a better idea anyway, but that's just the way that I think.

If you want to be safe about it, add another parameter that is the size of the array itself, and then do some marshalling. Again, though, you'll need to go into 1D arrays:

Instead, you want to do some marshalling, like so:

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

Then just call the function directly:

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

Your C++ would then change to:

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

If you want, you can add in the check against total length to ensure that you don't walk off the end, but that'll be a pretty big speed hit (enough to want to not use C++), as if statements aren't free.

Having done all of that, however, I have to ask-- why not just do this directly in C#, and save yourself the hassle of interop services like marshalling? C++ tends to be faster for complicated things, but for a quick array walk, I've seen C# behave pretty well. It can be pretty quick in C# too, once it's a 1D array:

 int i;
 for (i = 0; i < array.length; i++){
    array[i] *= scalar;
 }
mmr
That was a great help, I thank you