Best way to send byte[] parameter to unmanaged code?

P

Philippe Bertrand

Using C#, I want to send a byte array to an unmanaged function with the
minimum amount of copies. The array is input only and won't be modified
(its copied on the unmanaged side).

I'm currently using fixed byte *. My question is: Should I be using In
byte[] parameter instead? Ref parameter?

fixed( byte *b = byte_array ) {
MyUnmangedFunc2( b, byte_array.Length );
}

[DllImport("foo.dll")] private static extern unsafe void MyUnmanagedFunc2(
byte *val, int count );

--OR--

MyUnmanagedFunc2( byte_array, byte_array.Length );

[DllImport("foo.dll")] private static extern unsafe void MyUnmanagedFunc2(
In byte[] val, int count );


I need a solution for both the compact framework and desktop framework.
(Don't have to be the same but closer the better)

Thanks,
Philippe
 
N

Nicholas Paldino [.NET/C# MVP]

Philippe,

I would just use a byte[] parameter, and not in unsafe code. The
P/Invoke layer is doing something similar to fix the addresses of variables
when passing them to unmanaged code, so I don't see the need to do it again.

If you are not modifying the contents of the byte array often, you might
want to consider maintaining the byte array in unmanaged memory, and then
passing the IntPtr that points to that block of memory.

You could actually create a class that manages this for you quite
easily.

Hope this helps.
 
P

Philippe Bertrand

Will that work when I want the array to be an output parameter only? ie
there will be no hidden copying?

Is this correct?
// Accepts general arrays which will be read or copied
[DllImport("foo.dll")] private static extern void MyUnmanagedFunc2( In
byte[] val, int count );

// Fills general array (array must be at least count elements long)

[DllImport("foo.dll")] private static extern void MyUnmanagedFunc1( Out
byte[] val, int count );

Thanks,
Philippe
 
N

Nicholas Paldino [.NET/C# MVP]

Philippe,

That's a moot point because c-style arrays can not be marshaled from
unmanaged code to managed code (at least, not manually). You would have to
handle this yourself (possibly allocating memory and then deallocating upon
return).
 
P

Philippe Bertrand

I don't understand. My current implementation uses the same fixed( byte *p
= byte_array ) as I posted earlier and works. The unmanaged code modifies
the contents by copying into the array.

When the caller is not supplying the array to be filled, then yes I do
special handling for memory allocating and release. But when the caller
supplies the array to be filled, I don't have to do that. I just pass a
"fixed" pointer and the array size.

Philippe

Nicholas Paldino said:
Philippe,

That's a moot point because c-style arrays can not be marshaled from
unmanaged code to managed code (at least, not manually). You would have to
handle this yourself (possibly allocating memory and then deallocating upon
return).


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

Philippe Bertrand said:
Will that work when I want the array to be an output parameter only? ie
there will be no hidden copying?

Is this correct?
// Accepts general arrays which will be read or copied
[DllImport("foo.dll")] private static extern void MyUnmanagedFunc2( In
byte[] val, int count );

// Fills general array (array must be at least count elements long)

[DllImport("foo.dll")] private static extern void MyUnmanagedFunc1( Out
byte[] val, int count );

Thanks,
Philippe
 
L

Lasse Vågsæther Karlsen

When you pass a Byte[] array parameter to a unmanaged function, without
specific attributes to control the marshalling it will be marshalled as a
pointer to the bytes in the array.

As such, the unmanaged code can both read from and write to the bytes in
the array. Note that this can be a potential security leak as the code in
the unmanaged function does not check the bounds of the array when
writing (I mean, how could it) so you got a potential for buffer overrun
with this.

If your function doesn't keep the pointer around after it returns (as
some async functions does), then you don't need to do anything specific
when passing the Byte[] array. If the pointer is kept around by the
function you're calling you need to pin the array in managed memory to
avoid the GC moving it around and thus breaking the link between the
pointer and the byte array.

For this, you can check out the GCHandle class, something like:

GCHandle h = GCHandle.Allocate(byte_array, GCHandleType.Pinned);
try
{
// use h.AddrOfPinnedObject() here as the address of the bytes
}
finally
{
h.Free();
}
 

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