Search code examples
c#c++typesdoublepinvoke

PInvoke: Issue with returned array of doubles?


I am using PInvoke to call a C++ function from my C# program. The code looks like this:

IntPtr data = Poll(this.vhtHand);
double[] arr = new double[NR_FINGERS /* = 5 */ * NR_JOINTS /* = 3*/];
Marshal.Copy(data, arr, 0, arr.Length);

With Poll()'s signature looking like this:

[DllImport("VirtualHandBridge.dll")]
static public extern IntPtr Poll(IntPtr hand);

The C-function Poll's signature:

extern "C" __declspec(dllexport) double* Poll(CyberHand::Hand* hand)

Unless I'm having a huge brain failure (admittedly, fairly common for me), this looks to me like it should be working.

However, the double values I am getting are completely incorrect, and I think this is because of incorrect memory usage. I have looked it up, and I think doubles in C# and C++ are identical in size, but maybe there is some other issue playing here. One thing that rubs me the wrong way is that Marshal.Copy is never told what type of data it should expect, but I read that it is supposed to be used this way.

Any clues, anyone? If needed, I can post the correct results and the returned results.


Solution

  • You are missing the CallingConvention property, it is Cdecl.

    You really want to favor a better function signature, the one you have is extremely brittle due to the memory management problem, the required manual marshaling, the uncertainty of getting the right size array and the requirement to copy the data. Always favor the caller passing a buffer that your native code fills in:

    extern "C" __declspec(dllexport)
    int __stdcall Poll(CyberHand::Hand* hand, double* buffer, size_t bufferSize)
    
    [DllImport("foo.dll")]
    private static extern int Poll(IntPtr hand, double[] buffer, int bufferSize)
    

    Use the int return value to report a status code. Like a negative value to report an error code, a positive value to return the number of elements actually copied into the buffer.