how to wrap c++ char* to c# byte[] like MOgre

pizzazhang

01-10-2011 18:46:21

Hi, everyone,
I'm working on a game editor using c# now and I use swig to wrap c++ code to c#. I used to create render texture in MOgre and copy the pixel content to memory. Now the same code is written in c++, and I want to use it in c# and create a image from the pixel buffer. Let me explain better by showing code:
this is my c++ code that method passes a char[]
static void createTexFromMaterial(const std::string& matName, char* databuf);
then I create a render texture and copy the content
ASSERT(databuf && "data buff is null");
Ogre::PixelBox pb(256, 256, 1, Ogre::PF_A8R8G8B8, databuf);
// Tells the target to update it's contents.
rttTex->update();
rttTex->copyContentsToMemory(pb, Ogre::RenderTarget::FB_FRONT);

my c# code is like this:
byte[] buff = new byte[300 * 300 * 6];
// RenderUtil.createTexFromMaterial(material, ???);
MemoryStream ms = new MemoryStream(buff);
Image img = Image.FromStream(ms);
this.pictureBox1.Image = img;

the RenderUtil.createTexFromMaterial(material, ???) method expects a byte[] parameters but I don't know how to do this,
swig just automatically wrap my char* to string...
appreciate for any advice!

smiley80

01-10-2011 22:07:38

If you want to use P/Invoke then your native method has to look something like this:
extern "C"
{
__declspec(dllexport) void __stdcall createTexFromMaterial(const char* matName, char* databuf)
{
...
}
}


DllImport:
[DllImport(dllName)]
static extern void createTexFromMaterial(IntPtr matName, byte[] databuf);


Usage:
byte[] buff = new byte[300 * 300 * 6];
IntPtr str = Marshal.StringToHGlobalAnsi(material);
try
{
createTexFromMaterial(str, buff);
}
finally
{
Marshal.FreeHGlobal(str);
}

pizzazhang

02-10-2011 05:05:28

If you want to use P/Invoke then your native method has to look something like this:Thanks for your reply :D . But I'm using Swig to generate the interface so is there a *SWIG* way to do this?

smiley80

02-10-2011 15:12:37


%include "arrays_csharp.i"
%apply unsigned char INOUT[] {char *databuf}

pizzazhang

02-10-2011 17:09:46


%include "arrays_csharp.i"
%apply unsigned char INOUT[] {char *databuf}


I tried this, but not work. %apply unsigned char INOUT[] {unsigned char *databuf} swig will not recognize the unsigned char* so it will generate a file like Swig_p_unsigned_char which is not the type I want.
and %apply char INOUT[] {char *databuf} the generated method for c# expects a string parameters.

let me explain a bit better: I want pass a byte[] or IntPtr from c# to c++ code and c++ will copy something to the byte[] or IntPtr, and I want that result.
I also tried use typemap void* to IntPtr, but debug tells me ret value not correct or after c++ doing something to the byte[] parameters, it return it with nothing, all 0 in the byte array.
This problem bothers me a lot, and I google a lot but still could not fix it. If someone could help me solve it, it will be very very nice and I'll appreciate that! :D

smiley80

03-10-2011 19:21:53

Small correction:
%include "std_string.i"
%include "arrays_csharp.i"
CSHARP_ARRAYS(char, byte)
%apply char INOUT[] {char *databuf}


Tested with:
static void createTexFromMaterial(const std::string& matName, char* databuf)

Result:
public static void createTexFromMaterial(string matName, byte[] databuf)

pizzazhang

04-10-2011 05:23:37

Small correction:

really really thanks for your patience. the code is right, but not working for my case. Maybe I did something stupid.
I test the code with: char* test = new char[16];
test = "test once";
memcpy(data, test, 16*sizeof(test));

and I get the data in c# has its value which means c++ returned right.
but if I use the code: ASSERT(data && "data buff is null");
Ogre::PixelBox pb(256, 256, 1, Ogre::PF_A8R8G8B8, data);
// Tells the target to update it's contents.
rttTex->update();
rttTex->copyContentsToMemory(pb, Ogre::RenderTarget::FB_FRONT);

I just get empty byte[] data.