3

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
etwas77
  • 514
  • 1
  • 6
  • 17
  • As far as I know uint8_t != (C#)int. The correct one shouldbe byte. Also std::vector is not an array and I doubt you can copy it to C# like that. – floele Apr 08 '14 at 13:41
  • 1
    @floele You are mixed with where you are right and wrong. int!=uint8_t, int is a 32-but integer. `byte[]` in C# will work. The underlying data structure for std::vector is an array so this will work fine. protip: use std::vector.data instead of &(dataToCallback[0]). – IdeaHat Apr 08 '14 at 13:46
  • uint8_t is "casted" to IntPtr and not UIntPtr, because Marshal.Copy accepts only IntPtr. how else can you get data on c# side? – etwas77 Apr 08 '14 at 13:51
  • @etwas77 IntPtr in C# is a misnomer, it is really equivilent to a c++ `void*`. It is just a memory location. – IdeaHat Apr 08 '14 at 13:52
  • first, what you're trying to do is to call a c# function from C++ via the function pointer of that C# function? – Matt Apr 08 '14 at 13:58
  • @MadScienceDreams: Good to know thx, didn't expect `std::vector` to be an array internally. – floele Apr 08 '14 at 13:58

2 Answers2

2

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);
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

one thing to check is that on C# side you are expecting int-4 bytes per element ("int[] data") but on C++ you only allocating uint8-1 byte per element.

adjust the allocation or length usage, you could be getting access violation, that why you see magic bytes [1].

[1] http://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_debug_values

okigan
  • 1,559
  • 2
  • 18
  • 33
  • not sure what you mean. i supply proper data on c++ side (i see it in a debugger). when i land on c# side (still on debugger) and initialize array there using IntPtr and length, i get that thing. length is tranferred ok. obviously IntPtr points not to correct address.. what is wrong? – etwas77 Apr 08 '14 at 14:06
  • checkout this sample: http://inphamousdevelopment.wordpress.com/2012/10/01/sending-callbacks-from-c-to-c/ – okigan Apr 08 '14 at 14:36