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

Started by
8 comments, last by Naurava kulkuri 15 years, 7 months ago
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?
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 ReadCurrentFileint 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 memoryfixed (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.

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!
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.

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.
Rob Loach [Website] [Projects] [Contact]
Thanks!
Finally I correct my wrong concept about using unmanaged memory.
I'll figure out Tao's work some time for sure.
if you are only interested in unzipping a file, wouldn't a completly managed solution like sharp zip lib be more appropriate?
Also, in an unmanaged block, you can cast from void* to byte* though probably not byte[]
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
Quote:Original post by mutex
BTW there's #ziplib, a .NET ZIP library.
System.IO.Packaging and System.IO.Compression contain some useful content too.
---Sudet ulvovat - karavaani kulkee

This topic is closed to new replies.

Advertisement