Jump to content
  • Advertisement
Sign in to follow this  
HalfLucifer

[.net] From void* to byte[] ?

This topic is 3693 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to use an existing zip library written in C to write and read binary data from files. I managed to call library routines correctly by p/invoke method. When reading back binary data, I consider that MemoryStream class would be a right one to use. The question is, however, what I read from the old C library routine back is a void* type buffer that I failed to figure out how to appropriately match it to a byte[] array for MemoryStream class. The original routine signature in C: int ReadCurrentFile(FILE *file, void *buffer, unsigned int len); My p/invoke routine signature in C#: Int32 ReadCurrentFile(IntPtr file, out IntPtr buffer, UInt32 len); Any ideas or suggestions?

Share this post


Link to post
Share on other sites
Advertisement
Try Marshal.Copy(IntPtr source, byte[] destination, int startIndex, int length) to copy IntPtr to byte[]. Your P/Invoke definition looks incorrect, though. I believe you want Int32 ReadCurrentFile(IntPtr file, IntPtr buffer, UInt32 len) since buffer is an input pointer. Then usage would look like this:


Int32 ReadCurrentFile(IntPtr file, IntPtr buffer, UInt32 len);

// allocate buffer for ReadCurrentFile
int bufferSize = 512;
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
MemoryStream stream = null;
try
{
// perform file read
int readSize = ReadCurrentFile(file, buffer, bufferSize);

// copy IntPtr buffer to byte array
byte[] byteBuffer = new byte[bufferSize];
Marshal.Copy(buffer, byteBuffer, 0, readSize);
stream = new MemoryStream(byteBuffer);
}
finally
{
// always free the IntPtr buffer even if there's an exception
Marshal.FreeHGlobal(buffer);
}





However, the above has an extraneous buffer copy, and can be simplified to:


Int32 ReadCurrentFile(IntPtr file, IntPtr buffer, UInt32 len);

int bufferSize = 512;
int readSize;
byte[] buffer = new byte[bufferSize];

// prevent garbage collector from moving buffer around in memory
fixed (byte* fixedBuffer = buffer)
{
// get IntPtr representing address of first buffer element
IntPtr ptrBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
readSize = ReadCurrentFile(file, ptrBuffer, bufferSize);

// you might be able to do the following instead, but i'm not sure
readSize = ReadCurrentFile(file, (IntPtr)fixedBuffer, bufferSize);
}

MemoryStream stream = new MemoryStream(buffer);


BTW there's #ziplib, a .NET ZIP library.

Share this post


Link to post
Share on other sites
Thanks for your reply!
Marshal class is what I really need.

Here's my solution:
Int32 ReadCurrentFile(IntPtr file, IntPtr buffer, UInt32 len);

byte[] buffer = new byte[bufferSize];
IntPtr ptrBuffer = UnsafeAddrOfPinnedArrayElement(buffer, 0);
int readSize = ReadCurrentFile(file, ptrBuffer, bufferSize);
Marshal.Copy(ptrBuffer, buffer, 0, readSize);
MemoryStream ms = new MemoryStream(buffer);

And, thanks for the #ZipLib info. It's very useful!
I used to do zip work with zlib/minizip in C, though, now I've downloaded #ZipLib.
It looks pretty neat and intuitive. I'm sure I'll try it out!

Share this post


Link to post
Share on other sites
Quote:
Original post by HalfLucifer
Thanks for your reply!
Marshal class is what I really need.

Here's my solution:
Int32 ReadCurrentFile(IntPtr file, IntPtr buffer, UInt32 len);

byte[] buffer = new byte[bufferSize];
IntPtr ptrBuffer = UnsafeAddrOfPinnedArrayElement(buffer, 0);
int readSize = ReadCurrentFile(file, ptrBuffer, bufferSize);
Marshal.Copy(ptrBuffer, buffer, 0, readSize);
MemoryStream ms = new MemoryStream(buffer);

And, thanks for the #ZipLib info. It's very useful!
I used to do zip work with zlib/minizip in C, though, now I've downloaded #ZipLib.
It looks pretty neat and intuitive. I'm sure I'll try it out!
Your solution is incorrect. ptrBuffer and buffer are both the same block of memory, so you don't need the Marshal.Copy call. You do need to add a fixed (byte* p = buffer) { } around the UnsafeAddrOfPinnedArrayElement and ReadCurrentFile calls, though. The reason is that the .NET garbage collector may move buffer around in memory in between those calls, which would cause ptrBuffer to point to invalid memory. Your code should be like my second example.

Share this post


Link to post
Share on other sites
Sounds like you're trying to do something similar for what Tao.PhysFs did for PhysFS. PhysFS is pretty much a virtual file system that allows reading from zip files, directories, WAD files, like you were reading from normal files. Tao.PhysFs is just the .NET bindings... If you take a look at Fs.cs, you'll find a lot of marshal tricks. One particular one being:


public static PHYSFS_sint64 PHYSFS_read(IntPtr handle, out byte[] buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
IntPtr ptrBuffer;
PHYSFS_sint64 ret = PHYSFS_read(handle, out ptrBuffer, objSize, objCount);
buffer = new byte[objCount];
Marshal.Copy(ptrBuffer, buffer, 0, (int)objCount);
Marshal.FreeHGlobal(ptrBuffer);
return ret;
}

[DllImport(PHYSFS_NATIVE_LIBRARY, CallingConvention=CALLING_CONVENTION, EntryPoint="PHYSFS_read"), SuppressUnmanagedCodeSecurity]
public extern static PHYSFS_sint64 PHYSFS_read(IntPtr handle, IntPtr buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount);




As you can see, it uses the marshal to copy from the start of the byte* (IntPtr) to a byte[]. One thing you have to make sure you do is clear the memory if your unmanaged library allocated it for you.

Share this post


Link to post
Share on other sites
Hi HalfLucifer,

Try the following article:
http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx

It's an in depth article about marshalling between native code and managed code. It shows which types are interoperable, how to import a DLL, how to pass strings, how to pass structures and how to de-reference pointers.

It has all the answers on this problem

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!