Search code examples
c#c++pinvokemarshalling

how to marshal c++ array to c# via IntPtr


consider following setup: c# application with c++ library. c# elements are filled from c++ via callback. on c# side callback is defined like this:

void callbackTester(IntPtr pData, UInt32 length)
{
    int[] data = new int[length];
    Marshal.Copy(pData, data, (int)0, (int)length);
    //using data.. on c#
}

now, on c++ side callback is defined like this:

typedef void (__stdcall *func)(uint8_t* pdata, uint32_t length);

and c++ is using callback like this:

void onData()
{
    std::vector<uint8_t> dataToCallback;
    // fill in dataToCallback
    _callback(&(dataToCallback[0]), dataToCallback.size());
    // where _callback is a pointer to that c# function
}

my task: get array from c++ side on c# side using callback.

so, when c++ object is calling onData() function, it calls my callback from c#. so far so good. i have made a c++ tester program, which uses this, and i am receiving array correctly on callback side. if i am using it on c# tester, i am receiving crap.

for example: if i am sending uint8_t array of {1, 1}, i am getting {1, 1} for c++ tester, and i am getting {0xfeeeabab, 0xfeeefeee} on c# side... obviously, the conversion between uint8_t* c++ pointer and IntPtr c# is working not as i expect.

any suggestions? thanks a lot.


Solution

  • The issue appears to be that C++ uint8_t is an unsigned byte, and C# int is a signed 4 byte integer. So you have a simple mismatch of types. The C# type that matches uint8_t is byte.

    Your callback should be:

    void callbackTester(IntPtr pData, uint length)
    {
        byte[] data = new byte[length];
        Marshal.Copy(pData, data, 0, (int)length);
    }