conversion c#-bytearray to c++-char*

  • Thread starter Thread starter =?ISO-8859-2?Q?Marcin_Grz=EAbski?=
  • Start date Start date
?

=?ISO-8859-2?Q?Marcin_Grz=EAbski?=

Hi,

Quick tip:

replace "ref byte[]" with "StringBuilder" (System.Text)
e.g.:
private extern static void MyFunction(StringBuilder byteStream);

HTH

Marcin
 
Hmmm...
It works with APIs functions, but i may be wrong.

first of all... are you sure that this code do
what you want to do?

buffer = "Hello from managed c++!";

I worked with "string.h" (strcpy) to do any
string copies in past.
This function doesn't change your input "buffer"!
It change the reference only int function body.

Try using the "strcpy" and then check my code.

Regards

Marcin
 
yeah, I admit you may be right - but within managed c++, you cannot use
strcpy (unresolved external symbol)
do you know how to do that in managed c++?

if simple '#include <string.h>' doesn't work then
i have no idea.

I didn't work in managed C++.

Marcin
 
It's easy to convert a byte array to a string

byte[] byteStream = new byte[4000]; // create new byte stream
string buffer =
System.Text.Encoding.Unicode.GetString(byteStream,0,byteStream.Length);
MyFunction(ref buffer); // call c++ function
MessageBox.Show(buffer); // test-output the data

The System.Text.Encoding class also supports other encoding types in
addition to Unicode, check to see what suits you best.

Regards,
John Wadie
 
Ekim,

You have a few problems with this code. First, you are passing a
pointer to a character, this is the same as an array of characters.
However, inside the function, you are reassigning the pointer. Because the
pointer is what was actually passed to the function, the reassignment never
takes place (a copy of the pointer was passed in and the original is not
touched).

Now, you could change the parameter to a double pointer, but that would
be a bad idea. The reason for this is that you are causing a reassignment
to the original pointer, and you are not indicating the memory allocation
scheme (is it through the COM allocator, new, malloc). Because of this, you
might not be able to free the memory correctly.

Because of that, you should pass the pointer in to a pre-allocated
buffer (along with the length) and then copy the contents into the buffer.

Now, here is the problem. You say you can not change the type in C# to
any other data type. You must do this. The reason for this is that
marshaling through the P/Invoke layer does not marshal back arrays. The
reason for this is that the runtime doesn't know upon returning how much of
the array to marshal. Now, you can get around this by using a
StringBuilder, as suggested before, and allocating the buffer to a large
amount (in the case you can't change the C++ code). However, this will most
likely result in a memory leak of some kind, if the contents aren't copied
to the buffer, and you are just trying to reassign).

You could also marshal the contents manually, declaring the type as
IntPtr, and marshaling the array yourself across the boundary, and then
back, but that's not worth it, since you have the functionality using the
StringBuilder already. If anything, you can make the API call private, and
create a wrapper which performs the appropriate conversions.

Hope this helps.


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

Ekim said:
hy to all,

I'm accessing a function from a managed-c++-dll within my c#-application.
Therefore I encountered following troubles:
In my c#-app I have got a byte[]-array, which should somehow be mapped to
a
char* in my managed-c++-function.
Here is the prototype:
---------------------- managed c++ class library
project -------------------------------
void MyFunction(char* buffer)
{
buffer = "Hello from managed c++!";
}
----------------------------------------------------------------------------
------------

in c# I'm using this function like this:
-----------------------
c#-application -------------------------------------------------
[DllImport("c++ClassLib.dll")] // import the c++
dll
private extern static void MyFunction(ref byte[] byteStream);

within any function, for example button1-Click()
{
byte[] byteStream = new byte[4000]; // create new byte stream
MyFunction(ref byteStream); // call c++ function
MessageBox.Show(byteStream.toString()); // test-output the data
}
----------------------------------------------------------------------------
------------

The above code works (means throws no exception or something like this),
but
has not the desired effect (that is, a displayed messagebox that says
"Hello
from managed c++!"). So what I want to do in the c++-dll is to write
something into the byteStream that is provided by the c#-application).

Under no circumstances I can change the byte-stream to any other datatype
(because it is provided to me by another function), nor can I change the
char*-buffer in my c++-dll, because it is used by another external
function,
too.
On the other hand, I could use some "intermediate" data types like an
Array
if this would make things work (that is first converting the byteStream to
the Array, call the function, and within MyFunction convert the Array back
to char*).

I appreciate your help sincerely,

ekim!
 
Well, I haven't tried this method on such a huge amount of data before,
give it a try and let us know the results.

To convert the string back to a byte array:

byteStream = System.Text.Encoding.Unicode.GetBytes(buffer);

Regards,
John Wadie
 
Hi,

void MyFunction(char** buffer) // pointer to pointer!
{
*buffer = "Hello from managed c++!";
}

From my PoV this code will not work as you want it.
There is not much sense to return const string.

And any memory allocations (e.g. *buffer=new char[32])
will execute on "imported dll's" side.

But, if you want to fill the buffer (passed by reference)
then definition:
void MyFunction(char* buffer) // pointer to pointer!
{
FillTheBuffer(buffer);
}
will be more suitable here.

If you can not use functions of <string.h> then you can
define function:

void MyFunction(char* buffer, int bufferLength)
{
// e.g.
for(int i=0; i<(bufferLength-1); i++) {
buffer='a' + (i%('z'-'a'));
}
buffer='\0';
}

Maybe this link could help you:

http://groups.google.com/groups?hl=...&selm=eowbEXwuCHA.2516%40TK2MSFTNGP09&rnum=18

Marcin
 
hy to all,

I'm accessing a function from a managed-c++-dll within my c#-application.
Therefore I encountered following troubles:
In my c#-app I have got a byte[]-array, which should somehow be mapped to a
char* in my managed-c++-function.
Here is the prototype:
---------------------- managed c++ class library
project -------------------------------
void MyFunction(char* buffer)
{
buffer = "Hello from managed c++!";
}
----------------------------------------------------------------------------
------------

in c# I'm using this function like this:
-----------------------
c#-application -------------------------------------------------
[DllImport("c++ClassLib.dll")] // import the c++ dll
private extern static void MyFunction(ref byte[] byteStream);

within any function, for example button1-Click()
{
byte[] byteStream = new byte[4000]; // create new byte stream
MyFunction(ref byteStream); // call c++ function
MessageBox.Show(byteStream.toString()); // test-output the data
}
----------------------------------------------------------------------------
------------

The above code works (means throws no exception or something like this), but
has not the desired effect (that is, a displayed messagebox that says "Hello
from managed c++!"). So what I want to do in the c++-dll is to write
something into the byteStream that is provided by the c#-application).

Under no circumstances I can change the byte-stream to any other datatype
(because it is provided to me by another function), nor can I change the
char*-buffer in my c++-dll, because it is used by another external function,
too.
On the other hand, I could use some "intermediate" data types like an Array
if this would make things work (that is first converting the byteStream to
the Array, call the function, and within MyFunction convert the Array back
to char*).

I appreciate your help sincerely,

ekim!
 
Marcin Grzêbski said:
Hi,

Quick tip:

replace "ref byte[]" with "StringBuilder" (System.Text)
e.g.:
private extern static void MyFunction(StringBuilder byteStream);
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Under no circumstances I can change the byte-stream to any other datatype
(because it is provided to me by another function), nor can I change the
char*-buffer in my c++-dll, because it is used by another external function,
too.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

as I said before, I MUST use a byte-array. I thought it shouldn't be that
difficult, because as far as I know is a byte-array in C# (one byte per
element) the same as a char-array in C++ (one byte per element, too) -
nothingtheless, it doesn't work right now.

by ekim
 
Marcin Grzêbski said:
Hmmm...
It works with APIs functions, but i may be wrong.

first of all... are you sure that this code do
what you want to do?

buffer = "Hello from managed c++!";

I worked with "string.h" (strcpy) to do any
string copies in past.
This function doesn't change your input "buffer"!
It change the reference only int function body.

Try using the "strcpy" and then check my code.

Regards

Marcin

yeah, I admit you may be right - but within managed c++, you cannot use
strcpy (unresolved external symbol)
do you know how to do that in managed c++?

thx
 
Ekim said:
yeah, I admit you may be right - but within managed c++, you cannot use
strcpy (unresolved external symbol)
do you know how to do that in managed c++?

thx

okay, let me correct something - I've already tried to convert a string to
char*, and this works fine. it is done in this way:
---------------------- managed c++ class library
project -------------------------------
void MyFunction(char** buffer) // pointer to pointer!
{
*buffer = "Hello from managed c++!";
}
----------------------------------------------------------------------------

in c# I'm using this function like this:
-----------------------
c#-application -------------------------------------------------
[DllImport("c++ClassLib.dll")] // import the c++ dll
private extern static int ConvertPDF(ref string stringBuffer);

within any function, for example button1-Click()
{
string buffer = @"text before function"; // create new string
MyFunction(ref stringBuffer); // call c++ function
MessageBox.Show(stringBuffer); // test-output the data
}
----------------------------------------------------------------------------
------------

this code really works fine, means that it displays "Hello from managed C++"
in the messagebox. As far as I use a pointer to pointer (see code above), I
can make a statement like *buffer = "Hello from managed c++!";
and it works.

Anyways, once again I don't need a string but would need a byte-Array on the
Csharp-side instead.
 
John Wadie said:
It's easy to convert a byte array to a string

byte[] byteStream = new byte[4000]; // create new byte stream
string buffer =
System.Text.Encoding.Unicode.GetString(byteStream,0,byteStream.Length);
MyFunction(ref buffer); // call c++ function
MessageBox.Show(buffer); // test-output the data

The System.Text.Encoding class also supports other encoding types in
addition to Unicode, check to see what suits you best.

Regards,
John Wadie

hy john,
thx for your suggestion. Although I don't quite like the idea of converting
the byteStream first to a string, call the function and afterwards convert
it back into a byteStream, I guess that's a way it could serve me. (I don't
like it because it is a quite time-critical application that converts a lot
of files and is called thousand of times within a short period - therefore I
would have preferred a direct way, that is directly from byteArray to char*)
Besides the byteArray, before I call the function, is allocated, but has no
reasonable content, and therefore it's nonsense to convert it to a
Unicode-string.

So, my real question is now, how can I back-transform the string into a
byte-array?

by ekim
 
Ekim said:
hy to all,

I'm accessing a function from a managed-c++-dll within my c#-application.
Therefore I encountered following troubles:
In my c#-app I have got a byte[]-array, which should somehow be mapped to a
char* in my managed-c++-function.
Here is the prototype:
---------------------- managed c++ class library
project -------------------------------
void MyFunction(char* buffer)
{
buffer = "Hello from managed c++!";
}
-------------------------------------------------------------------------- --
------------

in c# I'm using this function like this:
-----------------------
c#-application -------------------------------------------------
[DllImport("c++ClassLib.dll")] // import the c++ dll
private extern static void MyFunction(ref byte[] byteStream);

within any function, for example button1-Click()
{
byte[] byteStream = new byte[4000]; // create new byte stream
MyFunction(ref byteStream); // call c++ function
MessageBox.Show(byteStream.toString()); // test-output the data
}
-------------------------------------------------------------------------- --
------------

The above code works (means throws no exception or something like this), but
has not the desired effect (that is, a displayed messagebox that says "Hello
from managed c++!"). So what I want to do in the c++-dll is to write
something into the byteStream that is provided by the c#-application).

Under no circumstances I can change the byte-stream to any other datatype
(because it is provided to me by another function), nor can I change the
char*-buffer in my c++-dll, because it is used by another external function,
too.
On the other hand, I could use some "intermediate" data types like an Array
if this would make things work (that is first converting the byteStream to
the Array, call the function, and within MyFunction convert the Array back
to char*).

I appreciate your help sincerely,

ekim!

after all, I figured out that there may be another good way in doing this:
I mean, I will give in the pre-allocated byteArray from C# to my
c++-function, and now as parameter of the c++-function it could be something
like byte __gc[] (instead of using char** buffer before).
I read something about this type, and that it belongs to something like the
so called managed c++ extensions - unfortunately, I didn't manage to make it
work yet.
But passing a byteArray from c# to c++ with this type could work I guess -
subsequently, I only have to find a method to fill the byte __gc[]-array
within my c++-function with the content of my char*-buffer.

Has anybody an idea if my described method could work (and how I have to
specify the parameters exactly) and how I could copy the char*-buffer into
the __gc[]-byteArray in managed c++?

thx again,
ekim
 
Back
Top