dealing with unsigned char* from C++ .lib

S

Stephen Cawood

I'm trying to use a C++ .lib from C# (I tried the Interop group will no
results).
I have a working wrapper DLL (I can get back simple things like int), but
I'm having issues dealing with an array of bytes.

For example, the .lib contains this function:

int create(int id, int scale, unsigned char *image);

In the wrapper DLL I have this function:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
return create(id, scale, image);
}

I also tried to return the unsigned char* like this:

WIN32DLL_API int create_wrapped_returnimage(int id, int scale, unsigned char
*image)
{
create(id, scale, image);
return image;
}

In C#, I've tried to access the functions like this:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale,[In, Out] IntPtr
image);

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
public static extern IntPtr create_wrapped_returnimage(int id, int
scale,[In] IntPtr image);

Then I try to manage the array like this:

IntPtr ptrArg = new IntPtr();
IntPtr unmanagedArray = create_wrapped_returnimage(0,5,ptrArg);
byte [] newArray = new byte[500];
Marshal.Copy(unmanagedArray, newArray, 0, 500);

I then checked what I have and get an error that this returns null:

label1.Text = unmanagedArray.GetType().ToString();

Eventually, I'll be converting the original byte array into an image, but
clearly I need to get this working first. I've tried various data types to
try and deal with the "unsigned char *image," but I haven't found a
solution.
Can someone suggest the best way to deal with this? Should I be converting
the unsigned char to a different type within the C++ wrapper function? If
so, some sample code would be helpful.

Thanks in advance.
 
N

Nicholas Paldino [.NET/C# MVP]

Stephen,

Does the function allocate the memory for the bytes? My guess is that
it doesn't. Otherwise, you would have a double reference to byte in the
unmanaged declaration.

However, it doesn't seem to have a mechanism to allow you to specify how
big the buffer is that you are passing to it. This is important, since you
don't want the API function to overwrite memory that does not belong to it.

Before I give an answer, can you show how you would call this (including
the code to set up any variables you are passing, as well as how you would
interpret or clean up those variables when done)? This way, we can indicate
what you have to do.
 
S

Stephen Cawood

thanks for the message, here are some more details.
this code is in my C++ wrapper, it includes a description of the function
and it writes the image out to a file. I was using it to test that the
wrapper was accessing the lib properly. I'd like to be able to do the same
from C#.

//-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise
//create() will fill an unsigned char array with 100*scale*scale bytes
WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
// This code writes the image out to a .PGM file
create(id, scale, image);
char *file_name = "test.pgm";
char *comment = "createimage";
int width = 10*scale;
int height = 10*scale;
FILE *out;
int i,j;
out=(FILE*)fopen(file_name,"wb");
if(out==NULL)
{printf("PGM_FUNCTIONS.C error: Couldn't open %s for
writing\n",file_name);exit(1);}
fprintf(out,"P5\n#%s\n",comment);
fprintf(out,"%d %d\n255\n",width,height);

for(i=0;i<width*height;i++)
{
j=(int)(*(image+i));
fputc(j,out);
}
fclose(out);
return create(id, scale, image);
}


Nicholas Paldino said:
Stephen,

Does the function allocate the memory for the bytes? My guess is that
it doesn't. Otherwise, you would have a double reference to byte in the
unmanaged declaration.

However, it doesn't seem to have a mechanism to allow you to specify
how big the buffer is that you are passing to it. This is important,
since you don't want the API function to overwrite memory that does not
belong to it.

Before I give an answer, can you show how you would call this
(including the code to set up any variables you are passing, as well as
how you would interpret or clean up those variables when done)? This way,
we can indicate what you have to do.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Stephen Cawood said:
I'm trying to use a C++ .lib from C# (I tried the Interop group will no
results).
I have a working wrapper DLL (I can get back simple things like int), but
I'm having issues dealing with an array of bytes.

For example, the .lib contains this function:

int create(int id, int scale, unsigned char *image);

In the wrapper DLL I have this function:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
return create(id, scale, image);
}

I also tried to return the unsigned char* like this:

WIN32DLL_API int create_wrapped_returnimage(int id, int scale, unsigned
char *image)
{
create(id, scale, image);
return image;
}

In C#, I've tried to access the functions like this:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale,[In, Out]
IntPtr image);

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
public static extern IntPtr create_wrapped_returnimage(int id, int
scale,[In] IntPtr image);

Then I try to manage the array like this:

IntPtr ptrArg = new IntPtr();
IntPtr unmanagedArray = create_wrapped_returnimage(0,5,ptrArg);
byte [] newArray = new byte[500];
Marshal.Copy(unmanagedArray, newArray, 0, 500);

I then checked what I have and get an error that this returns null:

label1.Text = unmanagedArray.GetType().ToString();

Eventually, I'll be converting the original byte array into an image, but
clearly I need to get this working first. I've tried various data types
to try and deal with the "unsigned char *image," but I haven't found a
solution.
Can someone suggest the best way to deal with this? Should I be
converting the unsigned char to a different type within the C++ wrapper
function? If so, some sample code would be helpful.

Thanks in advance.
 
S

Stephen Cawood

I got some advice from the interop group, but I am still working on the
problem. here's the current status...

I currently get the error "Can not marshall return type"
this is what I'm trying...


//Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
[return : MarshalAs(UnmanagedType.LPArray)]
public static extern byte[] create_wrapped_returnimage(int id, int scale,
[Out] byte[] image);

then to use it...

//Test with returnImage
byte[] bImage = new byte[2560];
bImage = create_wrapped_returnimage(0,5,bImage);


Stephen Cawood said:
thanks for the message, here are some more details.
this code is in my C++ wrapper, it includes a description of the function
and it writes the image out to a file. I was using it to test that the
wrapper was accessing the lib properly. I'd like to be able to do the same
from C#.

//-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise
//create() will fill an unsigned char array with 100*scale*scale bytes
WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
// This code writes the image out to a .PGM file
create(id, scale, image);
char *file_name = "test.pgm";
char *comment = "createimage";
int width = 10*scale;
int height = 10*scale;
FILE *out;
int i,j;
out=(FILE*)fopen(file_name,"wb");
if(out==NULL)
{printf("PGM_FUNCTIONS.C error: Couldn't open %s for
writing\n",file_name);exit(1);}
fprintf(out,"P5\n#%s\n",comment);
fprintf(out,"%d %d\n255\n",width,height);

for(i=0;i<width*height;i++)
{
j=(int)(*(image+i));
fputc(j,out);
}
fclose(out);
return create(id, scale, image);
}


Nicholas Paldino said:
Stephen,

Does the function allocate the memory for the bytes? My guess is that
it doesn't. Otherwise, you would have a double reference to byte in the
unmanaged declaration.

However, it doesn't seem to have a mechanism to allow you to specify
how big the buffer is that you are passing to it. This is important,
since you don't want the API function to overwrite memory that does not
belong to it.

Before I give an answer, can you show how you would call this
(including the code to set up any variables you are passing, as well as
how you would interpret or clean up those variables when done)? This
way, we can indicate what you have to do.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Stephen Cawood said:
I'm trying to use a C++ .lib from C# (I tried the Interop group will no
results).
I have a working wrapper DLL (I can get back simple things like int),
but I'm having issues dealing with an array of bytes.

For example, the .lib contains this function:

int create(int id, int scale, unsigned char *image);

In the wrapper DLL I have this function:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
return create(id, scale, image);
}

I also tried to return the unsigned char* like this:

WIN32DLL_API int create_wrapped_returnimage(int id, int scale, unsigned
char *image)
{
create(id, scale, image);
return image;
}

In C#, I've tried to access the functions like this:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale,[In, Out]
IntPtr image);

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
public static extern IntPtr create_wrapped_returnimage(int id, int
scale,[In] IntPtr image);

Then I try to manage the array like this:

IntPtr ptrArg = new IntPtr();
IntPtr unmanagedArray = create_wrapped_returnimage(0,5,ptrArg);
byte [] newArray = new byte[500];
Marshal.Copy(unmanagedArray, newArray, 0, 500);

I then checked what I have and get an error that this returns null:

label1.Text = unmanagedArray.GetType().ToString();

Eventually, I'll be converting the original byte array into an image,
but clearly I need to get this working first. I've tried various data
types to try and deal with the "unsigned char *image," but I haven't
found a solution.
Can someone suggest the best way to deal with this? Should I be
converting the unsigned char to a different type within the C++ wrapper
function? If so, some sample code would be helpful.

Thanks in advance.
 
S

Stephen Cawood

after some more advice, I'm trying this code, but the result is an array of
zeros. I don't seem to be getting the bytes.

wrapper DLL:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
return create(id, scale, image);
}

test C# form:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale, [Out] byte[]
image);

byte[] bArray = new byte[2560];
create_wrapped(0,5,bArray);

label1.Text = bArray[0].ToString();

the result is: 0
also, when I look in the debugger, the array is all zeros

BTW - when I check the return value of the function like this...

label1.Text = create_wrapped(0,5,bArray).ToString();

the result is: 0
(which is success)


notes:

/-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise

Stephen Cawood said:
I got some advice from the interop group, but I am still working on the
problem. here's the current status...

I currently get the error "Can not marshall return type"
this is what I'm trying...


//Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
[return : MarshalAs(UnmanagedType.LPArray)]
public static extern byte[] create_wrapped_returnimage(int id, int scale,
[Out] byte[] image);

then to use it...

//Test with returnImage
byte[] bImage = new byte[2560];
bImage = create_wrapped_returnimage(0,5,bImage);


Stephen Cawood said:
thanks for the message, here are some more details.
this code is in my C++ wrapper, it includes a description of the function
and it writes the image out to a file. I was using it to test that the
wrapper was accessing the lib properly. I'd like to be able to do the
same from C#.

//-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise
//create() will fill an unsigned char array with 100*scale*scale bytes
WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
// This code writes the image out to a .PGM file
create(id, scale, image);
char *file_name = "test.pgm";
char *comment = "createimage";
int width = 10*scale;
int height = 10*scale;
FILE *out;
int i,j;
out=(FILE*)fopen(file_name,"wb");
if(out==NULL)
{printf("PGM_FUNCTIONS.C error: Couldn't open %s for
writing\n",file_name);exit(1);}
fprintf(out,"P5\n#%s\n",comment);
fprintf(out,"%d %d\n255\n",width,height);

for(i=0;i<width*height;i++)
{
j=(int)(*(image+i));
fputc(j,out);
}
fclose(out);
return create(id, scale, image);
}


Nicholas Paldino said:
Stephen,

Does the function allocate the memory for the bytes? My guess is
that it doesn't. Otherwise, you would have a double reference to byte
in the unmanaged declaration.

However, it doesn't seem to have a mechanism to allow you to specify
how big the buffer is that you are passing to it. This is important,
since you don't want the API function to overwrite memory that does not
belong to it.

Before I give an answer, can you show how you would call this
(including the code to set up any variables you are passing, as well as
how you would interpret or clean up those variables when done)? This
way, we can indicate what you have to do.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I'm trying to use a C++ .lib from C# (I tried the Interop group will no
results).
I have a working wrapper DLL (I can get back simple things like int),
but I'm having issues dealing with an array of bytes.

For example, the .lib contains this function:

int create(int id, int scale, unsigned char *image);

In the wrapper DLL I have this function:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char
*image)
{
return create(id, scale, image);
}

I also tried to return the unsigned char* like this:

WIN32DLL_API int create_wrapped_returnimage(int id, int scale, unsigned
char *image)
{
create(id, scale, image);
return image;
}

In C#, I've tried to access the functions like this:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale,[In, Out]
IntPtr image);

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
public static extern IntPtr create_wrapped_returnimage(int id, int
scale,[In] IntPtr image);

Then I try to manage the array like this:

IntPtr ptrArg = new IntPtr();
IntPtr unmanagedArray = create_wrapped_returnimage(0,5,ptrArg);
byte [] newArray = new byte[500];
Marshal.Copy(unmanagedArray, newArray, 0, 500);

I then checked what I have and get an error that this returns null:

label1.Text = unmanagedArray.GetType().ToString();

Eventually, I'll be converting the original byte array into an image,
but clearly I need to get this working first. I've tried various data
types to try and deal with the "unsigned char *image," but I haven't
found a solution.
Can someone suggest the best way to deal with this? Should I be
converting the unsigned char to a different type within the C++ wrapper
function? If so, some sample code would be helpful.

Thanks in advance.
 
S

Stephen Cawood

it works! wow, this took some time. anyway, here's the winning combination.
thanks again.


C .lib
-------------------
/-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise

int create(int id, int scale, unsigned char *image);


C++ Wrapper
-------------------

WRAPPER_API int create_wrapped(int id, int scale, void** image)
{
int retCode = -1;
unsigned char* ptrImage = NULL;

if ( NULL != *image )
{
ptrImage = (unsigned char*)GlobalLock(*image);
retCode = create(id, scale, ptrImage);
GlobalUnlock(*image);
}
else
{
retCode = create(id, scale, ptrImage);
*image = (void*)ptrImage;
}

return retCode;

}


C# Accessing the wrapper function
-------------------
// create
[DllImport("Wrapper.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale, [In][Out] ref
IntPtr image);


C# Using the data
-------------------

// Allocate unmanaged memory - must be freed with
Marshal.FreeHGlobal(ptrImage)
IntPtr ptrImage = Marshal.AllocHGlobal(2500);


// Try to copy the unmanaged bytes to a managed array
try
{
// Get a pointer to an unmanaged byte array which contains the image
label1.Text = create_wrapped(0, 5, ref ptrImage).ToString(); //return 0 for
success
byte[] bManagedArray = new byte[2500];

// Read through entire pointer byte by byte and put into managed array
for (int i = 0; i < bManagedArray.Length; i++)
{
bManagedArray = Marshal.ReadByte(ptrImage, i);
}


// custom function to Write the PGM image out to a file
writeImageToFile(bManagedArray);

}
catch (ArgumentNullException ex)
{
MessageBox.Show(ex.Message, "Marshal Copy Error", MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(ptrImage);
}

Stephen Cawood said:
after some more advice, I'm trying this code, but the result is an array
of zeros. I don't seem to be getting the bytes.

wrapper DLL:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
return create(id, scale, image);
}

test C# form:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale, [Out] byte[]
image);

byte[] bArray = new byte[2560];
create_wrapped(0,5,bArray);

label1.Text = bArray[0].ToString();

the result is: 0
also, when I look in the debugger, the array is all zeros

BTW - when I check the return value of the function like this...

label1.Text = create_wrapped(0,5,bArray).ToString();

the result is: 0
(which is success)


notes:

/-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise

Stephen Cawood said:
I got some advice from the interop group, but I am still working on the
problem. here's the current status...

I currently get the error "Can not marshall return type"
this is what I'm trying...


//Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
[return : MarshalAs(UnmanagedType.LPArray)]
public static extern byte[] create_wrapped_returnimage(int id, int scale,
[Out] byte[] image);

then to use it...

//Test with returnImage
byte[] bImage = new byte[2560];
bImage = create_wrapped_returnimage(0,5,bImage);


Stephen Cawood said:
thanks for the message, here are some more details.
this code is in my C++ wrapper, it includes a description of the
function and it writes the image out to a file. I was using it to test
that the wrapper was accessing the lib properly. I'd like to be able to
do the same from C#.

//-Call create() to create a bitmap of (10*scale) x (*10*scale) bytes
//create() will fill an unsigned char array with 100*scale*scale bytes
//
//create ID=567, 5 pixels/bit, total image will be 50x50 pixels
//this function will malloc room if image is NULL
//returns -1 if problem, 0 otherwise
//create() will fill an unsigned char array with 100*scale*scale bytes
WIN32DLL_API int create_wrapped(int id, int scale, unsigned char *image)
{
// This code writes the image out to a .PGM file
create(id, scale, image);
char *file_name = "test.pgm";
char *comment = "createimage";
int width = 10*scale;
int height = 10*scale;
FILE *out;
int i,j;
out=(FILE*)fopen(file_name,"wb");
if(out==NULL)
{printf("PGM_FUNCTIONS.C error: Couldn't open %s for
writing\n",file_name);exit(1);}
fprintf(out,"P5\n#%s\n",comment);
fprintf(out,"%d %d\n255\n",width,height);

for(i=0;i<width*height;i++)
{
j=(int)(*(image+i));
fputc(j,out);
}
fclose(out);
return create(id, scale, image);
}


in message Stephen,

Does the function allocate the memory for the bytes? My guess is
that it doesn't. Otherwise, you would have a double reference to byte
in the unmanaged declaration.

However, it doesn't seem to have a mechanism to allow you to specify
how big the buffer is that you are passing to it. This is important,
since you don't want the API function to overwrite memory that does not
belong to it.

Before I give an answer, can you show how you would call this
(including the code to set up any variables you are passing, as well as
how you would interpret or clean up those variables when done)? This
way, we can indicate what you have to do.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I'm trying to use a C++ .lib from C# (I tried the Interop group will
no results).
I have a working wrapper DLL (I can get back simple things like int),
but I'm having issues dealing with an array of bytes.

For example, the .lib contains this function:

int create(int id, int scale, unsigned char *image);

In the wrapper DLL I have this function:

WIN32DLL_API int create_wrapped(int id, int scale, unsigned char
*image)
{
return create(id, scale, image);
}

I also tried to return the unsigned char* like this:

WIN32DLL_API int create_wrapped_returnimage(int id, int scale,
unsigned char *image)
{
create(id, scale, image);
return image;
}

In C#, I've tried to access the functions like this:

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped")]
public static extern int create_wrapped(int id, int scale,[In, Out]
IntPtr image);

[DllImport("Win32DLL.dll", EntryPoint="create_wrapped_returnimage")]
public static extern IntPtr create_wrapped_returnimage(int id, int
scale,[In] IntPtr image);

Then I try to manage the array like this:

IntPtr ptrArg = new IntPtr();
IntPtr unmanagedArray = create_wrapped_returnimage(0,5,ptrArg);
byte [] newArray = new byte[500];
Marshal.Copy(unmanagedArray, newArray, 0, 500);

I then checked what I have and get an error that this returns null:

label1.Text = unmanagedArray.GetType().ToString();

Eventually, I'll be converting the original byte array into an image,
but clearly I need to get this working first. I've tried various data
types to try and deal with the "unsigned char *image," but I haven't
found a solution.
Can someone suggest the best way to deal with this? Should I be
converting the unsigned char to a different type within the C++
wrapper function? If so, some sample code would be helpful.

Thanks in advance.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top