pass byte-array by reference from c# to managed c++

  • Thread starter Jon Skeet [C# MVP]
  • Start date
J

Jon Skeet [C# MVP]

Ekim said:
I'm allocating a byte-Array in C# with byte[] byteArray = new byte[5000];

Now I want to pass this byte-Array to a managed C++-function by reference,
so that I'm able to change the content of the byteArray and afterwards see
the changes in C#.
(if you wanna know more details: the goal is to write the content of an
existing char-array in c++ precisely into the passed byteArray, so that
after the function has proceded the content of the byteArray in C# equals
the content of the char-Array of C++.)

So I hope you understand what I'm about to do - unfortunately, I have no
clue how to do this.

I don't think you need to pass byteArray by reference at all - you'd
need to do that only if you were trying to change the value of byte
array itself - i.e. change it to a completely different array.

I would *hope* that you could just pass the reference by value (as
normal) and receive it as char* in the C code, but I'm far from an
interop expert. Have you tried asking on the .interop group?
 
J

Jon Skeet [C# MVP]

Ekim said:
Lately, I tried using a
int dummy(Byte array __gc[]) // c++ function
{
copy charArray into byteArray
}

and calling it from C# like
byte[] array = new byte[5000]; // allocate new byte-Array
dummy(ref array); // call c++-function
// in this place, the byteArray-content shall be the same as the
charArray-content I copied from

by the way, I tried it in C# with and without "ref" - neither did work.

the queer thing about it is, when I debug my app as soon as "dummy" gets
called, the byteArray is somehow truncated to the length 1 (instead of
5000).
does somebody know what I did wrong?

Ah, hang on - I hadn't noticed that it was *managed* C++. You should be
able to do that with no problems, and you definitely shouldn't need to
pass by reference.

Given the signature for Encoding.GetString in MC++, you should try

int dummy(unsigned char __gc[])
 
J

Jon Skeet [C# MVP]

Ekim said:
okay, you say it should work without any problems? unfortunately, it
doesn't.
here I show you what I tried to do now:

[DllImport("MyC++DLL.dll")]
private extern static int dummy(byte[] array);


Why are you using DllImport at all? Just add a reference to the MC++
DLL. DllImport is (as I understand it) for making calls to *unmanaged*
code.
btw.: what did you mean with:
"Given the signature for Encoding.GetString in MC++, you should try..."

I was trying to find the MC++ syntax of a signature of a method which
takes a byte array.
 
J

Jon Skeet [C# MVP]

Ekim said:
yeah, you are right - DllImport is for so called "P/Invoke" - calls to
unmanaged DLL's.
How can I "just" add a reference to a MC++-dll???

If it's a project in the same solution, you may well be able to add a
project reference. Otherwise, you need to find the file and add a
reference to that. In either case, right-click on the "References" part
of your project, and select "Add Reference" - the rest should be
obvious.
 
W

Willy Denoyette [MVP]

Here's a sample.

// Compile from commandline : cl /clr wrapper.cpp
// Wrapper.cpp
#include <strsafe.h> // used by safe string functions
public __gc class C
{
public:
void FillArray( System::Byte bArray __gc[])
{
char *ch = new char[ bArray->Length ]; // allocate native char buffer
StringCbCat( ch, bArray->Length, "dogs like cats like mice" );// copy
some text into buffer (here using safe string functions)
// copy unmanaged buffer to managed array
for (int i = 0; i < bArray->Length ; i++ )
{
bArray = ch;
}

delete[] ch;
}
};

// compile from commandline using csc /r:wrapper.dll tester.cs

// Tester.cs
class Tester
{
static void Main()
{
byte[] ba = new Byte[5000];
C c = new C();
c.FillArray(ba);
foreach(byte b in ba)
{
Console.WriteLine(b.ToString());
}

}
}


Willy.
 
N

Nicholas Paldino [.NET/C# MVP]

Ekim,

Are you sure you want to use a managed class for this? You posted
yesterday (btw, your system time or your newsreader posting time is off, if
you could change it so that you don't bottom-post, it would be appreciated)
regarding passing an array to C code. If you have a class in C++ and you
want to expose it to managed code, then I would say to go with Jon's or
Willy's recommendations, but I don't think that is what you have, or want.
I believe you have a piece of legacy C code that exports a function, and you
want to call it from C#.

Is this the case?

If it is, then the function header seems to indicate that you want to
copy content into a buffer. That is fine, but interop doesn't handle
C-style arrays correctly. It doesn't know how much information to marshal
back across the boundary. Because of this, you will have to marshal it
yourself. Now there are two ways you can go about this. The first is to
use unsafe code. You would declare your function like this:

[DllImport("myfunc.dll")]
private static extern unsafe int dummy(byte *array);

Then, in your code, you would call in an unsafe block, like this:

// The byte array.
byte[] bytes = new byte[5000];

// Declare an unsafe block, or you can put this on the method.
unsafe
{
// Fix the byte array.
fixed (byte *array = bytes)
{
// Make the call here, passing in the array.
int retVal = dummy(array);
}
}

What the above code does is it creates a managed array, and then fixes
the location in memory, then passes that pointer to the unmanaged function.

Of course, you have to compile the above code with the unsafe flag
(check the project properties).

The other way to do it would be to take a block of unmanaged memory and
pass that to the function, declaring the parameter as an IntPtr, and then
copying the contents to the managed realm. If you want, I can provide an
example of that as well (it's just more tedious to type).

Hope this helps.
 
W

Willy Denoyette [MVP]

..
Nicholas Paldino said:
Ekim,

Are you sure you want to use a managed class for this? You posted
yesterday (btw, your system time or your newsreader posting time is off,
if you could change it so that you don't bottom-post, it would be
appreciated) regarding passing an array to C code. If you have a class in
C++ and you want to expose it to managed code, then I would say to go with
Jon's or Willy's recommendations, but I don't think that is what you have,
or want. I believe you have a piece of legacy C code that exports a
function, and you want to call it from C#.

Is this the case?

If it is, then the function header seems to indicate that you want to
copy content into a buffer. That is fine, but interop doesn't handle
C-style arrays correctly. It doesn't know how much information to marshal
back across the boundary. Because of this, you will have to marshal it
yourself. Now there are two ways you can go about this. The first is to
use unsafe code. You would declare your function like this:

[DllImport("myfunc.dll")]
private static extern unsafe int dummy(byte *array);

Then, in your code, you would call in an unsafe block, like this:

// The byte array.
byte[] bytes = new byte[5000];

// Declare an unsafe block, or you can put this on the method.
unsafe
{
// Fix the byte array.
fixed (byte *array = bytes)
{
// Make the call here, passing in the array.
int retVal = dummy(array);
}
}

What the above code does is it creates a managed array, and then fixes
the location in memory, then passes that pointer to the unmanaged
function.

Of course, you have to compile the above code with the unsafe flag
(check the project properties).

The other way to do it would be to take a block of unmanaged memory and
pass that to the function, declaring the parameter as an IntPtr, and then
copying the contents to the managed realm. If you want, I can provide an
example of that as well (it's just more tedious to type).

Hope this helps.


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

Ekim said:
hello,
I'm allocating a byte-Array in C# with byte[] byteArray = new byte[5000];

Now I want to pass this byte-Array to a managed C++-function by
reference,
so that I'm able to change the content of the byteArray and afterwards
see
the changes in C#.
(if you wanna know more details: the goal is to write the content of an
existing char-array in c++ precisely into the passed byteArray, so that
after the function has proceded the content of the byteArray in C# equals
the content of the char-Array of C++.)

So I hope you understand what I'm about to do - unfortunately, I have no
clue how to do this.
However, I appreciate any help,

by ekim


Nicholas,

I agree, this confuses us all, but as OP was talking about passing a -
byte-Array to a managed C++-function - I assumed he was not talking about
unmanaged C++.
The confusing part here is that OP used the term 'function'. When using
'function' you effectively mean a C-Style API not a C++ class
(managed/unmanaged) method.
'Functions' (managed or unmanaged code) can ONLY be called from managed code
(other than MC++) through PInvoke interop, or from managed C++ through IJW.
In contrast, managed C++ methods can be called directly from any managed
language, while unmanaged methods can only be called from managed C++
through IJW.
So what I did is give a MC++ sample using a managed class that calls a C
function using IJW interop.

Willy.
 
E

Ekim

hello,
I'm allocating a byte-Array in C# with byte[] byteArray = new byte[5000];

Now I want to pass this byte-Array to a managed C++-function by reference,
so that I'm able to change the content of the byteArray and afterwards see
the changes in C#.
(if you wanna know more details: the goal is to write the content of an
existing char-array in c++ precisely into the passed byteArray, so that
after the function has proceded the content of the byteArray in C# equals
the content of the char-Array of C++.)

So I hope you understand what I'm about to do - unfortunately, I have no
clue how to do this.
However, I appreciate any help,

by ekim
 
E

Ekim

Jon Skeet said:
Ekim said:
I'm allocating a byte-Array in C# with byte[] byteArray = new byte[5000];

Now I want to pass this byte-Array to a managed C++-function by reference,
so that I'm able to change the content of the byteArray and afterwards see
the changes in C#.
(if you wanna know more details: the goal is to write the content of an
existing char-array in c++ precisely into the passed byteArray, so that
after the function has proceded the content of the byteArray in C# equals
the content of the char-Array of C++.)

So I hope you understand what I'm about to do - unfortunately, I have no
clue how to do this.

I don't think you need to pass byteArray by reference at all - you'd
need to do that only if you were trying to change the value of byte
array itself - i.e. change it to a completely different array.

I would *hope* that you could just pass the reference by value (as
normal) and receive it as char* in the C code, but I'm far from an
interop expert. Have you tried asking on the .interop group?

Yes, I tries asking in the .interop-ng, but no answers 'til now ;-(
yeah in fact I "only" have to change the content of the byteArray, not its
address or size as you might think.
But I don't know how to do that also!?

ekim
 
E

Ekim

Lately, I tried using a
int dummy(Byte array __gc[]) // c++ function
{
copy charArray into byteArray
}

and calling it from C# like
byte[] array = new byte[5000]; // allocate new byte-Array
dummy(ref array); // call c++-function
// in this place, the byteArray-content shall be the same as the
charArray-content I copied from

by the way, I tried it in C# with and without "ref" - neither did work.

the queer thing about it is, when I debug my app as soon as "dummy" gets
called, the byteArray is somehow truncated to the length 1 (instead of
5000).
does somebody know what I did wrong?
 
E

Ekim

hello,

YES, I am - although I must admit I articulated a little bit unprecisely
yesterday!


NO, but thx a lot for all your efforts - I'm currently already able to pass
a byteArray in and out (and change the content in my method).
The confusing part here is that OP used the term 'function'. When using
'function' you effectively mean a C-Style API not a C++ class
(managed/unmanaged) method.

OK, I always called it function - and because I didn't use classes, I guess
this is correct (I didn't use classes because of other circumstances, that
is because I have to write a CallbackFunction, which is called by another
dll (this time a real unmanaged one), and this CallbackFunction doesn't have
to be within a managed class.)
 
E

Ekim

Jon Skeet said:
Ekim said:
Lately, I tried using a
int dummy(Byte array __gc[]) // c++ function
{
copy charArray into byteArray
}

and calling it from C# like
byte[] array = new byte[5000]; // allocate new byte-Array
dummy(ref array); // call c++-function
// in this place, the byteArray-content shall be the same as the
charArray-content I copied from

by the way, I tried it in C# with and without "ref" - neither did work.

the queer thing about it is, when I debug my app as soon as "dummy" gets
called, the byteArray is somehow truncated to the length 1 (instead of
5000).
does somebody know what I did wrong?

Ah, hang on - I hadn't noticed that it was *managed* C++. You should be
able to do that with no problems, and you definitely shouldn't need to
pass by reference.

Given the signature for Encoding.GetString in MC++, you should try

int dummy(unsigned char __gc[])

okay, you say it should work without any problems? unfortunately, it
doesn't.
here I show you what I tried to do now:

------------- managed c++ class library ------------------------------
extern "C" __declspec(dllexport)
int dummy(unsigned char array __gc[])
{ ... /* copy the content of my char-array into the provided array-buffer
from C# */
// e.g.:
array[0] = myCharArray[0];
array[1] = myCharArray[1];
...
}
-----------------------------------------------------------------------

-------------- C#- app -----------------------------------------------
[DllImport("MyC++DLL.dll")]
private extern static int dummy(byte[] array);

within any function, for example button1_Click(), do:
{
byte[] byteArray = new byte[5000]; // allocate empty byteArray
dummy(byteArray); // call c++-function, and change the
content of the array in there
// now when I dump the byteArray, it shall have the same content as the
char-buffer where I copied from
}
------------------------------------------------------------------------

I hope you understand now clearly what I am about to do.
Anyways, this code doesn't work. When I debug the app, as soon as dummy is
called, the unsigned char array __gc[]) from C++ has only size = 1 instead
of 5000 (and therefore I'm not able to write into this buffer currently).

Hope someone can tell me the correct way before total despair of mine ;-/

ekim!

btw.: what did you mean with:
"Given the signature for Encoding.GetString in MC++, you should try..."
 
E

Ekim

hy,
after long studying and mostly because of all your provided help I was now
able to solve my problem totally.
Therefore once again I want to thank you - I really appreciate it.

kind regards,
ekim!
 
W

Willy Denoyette [MVP]

Ekim said:
hello,

YES, I am - although I must admit I articulated a little bit unprecisely yesterday!

OK, I always called it function - and because I didn't use classes, I
guess
this is correct (I didn't use classes because of other circumstances, that
is because I have to write a CallbackFunction, which is called by another
dll (this time a real unmanaged one), and this CallbackFunction doesn't
have
to be within a managed class.)
----------------------------------------------------------------------------

But you don't have to use MC++ for this, using C# you can declare a delegate
and pass this one as callback to your unmanaged function.
Declare your delegate taking an IntPtr as argument for the unmanaged buffer
address (the char*).
When the callback is called you can simply copy the buffer pointed to by the
IntPtr to a managed array using Marshal.Copy(IntPtr, dest, 0, length).

Willy.
 
E

Ekim

Why are you using DllImport at all? Just add a reference to the MC++
DLL. DllImport is (as I understand it) for making calls to *unmanaged*
code.

yeah, you are right - DllImport is for so called "P/Invoke" - calls to
unmanaged DLL's.
How can I "just" add a reference to a MC++-dll???

thx, ekim
 
E

Ekim

Willy Denoyette said:
Here's a sample.

// Compile from commandline : cl /clr wrapper.cpp
// Wrapper.cpp
#include <strsafe.h> // used by safe string functions
public __gc class C
{
public:
void FillArray( System::Byte bArray __gc[])
{
char *ch = new char[ bArray->Length ]; // allocate native char buffer
StringCbCat( ch, bArray->Length, "dogs like cats like mice" );// copy
some text into buffer (here using safe string functions)
// copy unmanaged buffer to managed array
for (int i = 0; i < bArray->Length ; i++ )
{
bArray = ch;
}

delete[] ch;
}
};

// compile from commandline using csc /r:wrapper.dll tester.cs

// Tester.cs
class Tester
{
static void Main()
{
byte[] ba = new Byte[5000];
C c = new C();
c.FillArray(ba);
foreach(byte b in ba)
{
Console.WriteLine(b.ToString());
}

}
}


Willy.


BIG THANKS to all of you - the above code is "quite" exactly what I was
looking for.
My real problem was that I imported the MC++ -DLL in the wrong way, that is
by setting
[DllImport("07_P2TClassLib.dll")]
private extern static int MyFunction(...);

But as far as I know, this is something like a so called P/Invoke-statement
and is only necessary for using unmanaged dll's.
In fact, now I added the MC++ and the C# project into the same solution and
added the dll just as a reference.
Therefore copying some chars into a C#-byteArray with the above provided
function works now.

But now I'm facing another problem:
Am I right that I have to "pack" the c++ functions into a Class? It would be
great if there is another way, too (simply accessing a lose function, not a
member function).

The thing is that I cannot copy the chars into the byteArray in MyFunction()
as I described earlier - no, things are much more difficult: - instead, I
make a call to another external function, which calls a CallBackFunction and
in there the char-buffer is passed to me. Unfortunately, because the
function is from an external vendor, I cannot pack the CallBackFunction into
the class, and I cannot pass parameters (like the byteArray) to the
CallbackFunction).

What I need now is a global tempBuffer where I can copy the data within the
CallbackFunction in the meantime for later use.
So I'm looking either for a global managed byteArray (when declaring
static Byte tempArray __gc[]; as global, I get an error message that global
variables are not allowed for managed types) - or using unmanaged C I would
like to use something like
char* tempBuffer = new char[100];
But it seems that the "new" operator isn't allowed here in managed c++ for
chars --> I always get the message "unresolved external symbol".

Maybe one of you guys knows an answer to that problem, also.
If not, doesn't matter toooo much, because you were already a great, great
help to me - THX AGAIN!!!!

by ekim
 
E

Ekim

Willy Denoyette said:
--

But you don't have to use MC++ for this, using C# you can declare a delegate
and pass this one as callback to your unmanaged function.
Declare your delegate taking an IntPtr as argument for the unmanaged buffer
address (the char*).
When the callback is called you can simply copy the buffer pointed to by the
IntPtr to a managed array using Marshal.Copy(IntPtr, dest, 0, length).

Willy.

yeah, that might be true - but my reason not using c# directly was that I
have to include something like a "converter.h"-file to be able to use the
pdf-converting-function from my external vendor --> and as far as I know I
cannot include a header ".h" file in c#.

by ekim
 

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