1

I have a dll which has arguments with double*, eg xyz(double* a, double* b). I am using this DLL to pass two double arrays to function xyz. The problem is when I'm passing a double array by reference using a, the array is being updated but the values are rounded off which happens when you typecast something to and from int. Can you tell me an efficient way of sending this double array to c dll and getting the desired results in decimal. (Changing the DLL is not an option). Also I tried Marshal, I am not entirely sure if I did the right thing, but whenever I used to change the argument of xyz to xyz(IntPtr a, double* b) or something I used to get AccessViolationException, corrupt memory.

  • Declare the arguments as `double[]` and pass the array. Very simple. You perhaps wrongly used `ref double[]` but we can't know because you didn't show the code. – David Heffernan May 05 '20 at 08:56
  • Judging from your comments about "rounded off" and "decimal" I wonder if there's actually nothing wrong with your interop, and perhaps your problem is really addressed here: https://stackoverflow.com/questions/588004/is-floating-point-math-broken – David Heffernan May 05 '20 at 09:00

2 Answers2

1

Try following :

            double[] a = { 1.23, 2.34, 5.45 };
            IntPtr aptr = Marshal.AllocHGlobal(a.Length * sizeof(double));
            Marshal.Copy(a, 0, aptr, a.Length);
            double[] b = { 1.23, 2.34, 5.45 };
            IntPtr bptr = Marshal.AllocHGlobal(b.Length * sizeof(double));
            Marshal.Copy(b, 0, bptr, b.Length);

            xyz(aptr, bptr)
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • No need to do this. Declare the argument as `double[]` and then simply pass the array. The marshaller will pin the array and pass the address of its first element. That's more efficient than allocate and copy. – David Heffernan May 05 '20 at 08:55
0

If I understand correctly, you are passing an array from C# to C (or C++) code. The problem with the approach of sending in the array directly to the method like xyz(double* a, double* b) is that the the code has no way of knowing the sizes of the arrays. This can get you access violation exceptions, once the C/C++ code tries to access an element that is out of the bounds of the array.

There are multiple ways around this - either using SafeArray from C# (that already contains the size attribute), sending the arrays to some bridging method with the sizes, or passing the data in a struct, like this:

internal struct ArraysStruct
{
    public int floatArraySize;
    public IntPtr floatArray;
    public int uintArraySize;
    public IntPtr uintArray; 
}

Which would then be matched on the C/C++ side by something like:

typedef struct ArraysStruct
{
    size_t floatArraySize;
    float* floatArray;
    size_t uintArraySize;
    unsigned int* uintArray;
}

You would need to use Marshal.AllocHGlobal() to allocate the arrays to the sizes first (in C#) and then Marshal.FreeHGlobal() once you're done with them.

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
George H.
  • 81
  • 1
  • 4