[.net] From void* to byte[] ?
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?
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:
However, the above has an extraneous buffer copy, and can be simplified to:
BTW there's #ziplib, a .NET ZIP library.
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);
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!
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 HalfLuciferYour 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.
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!
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:
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.
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.
Thanks!
Finally I correct my wrong concept about using unmanaged memory.
I'll figure out Tao's work some time for sure.
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?
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
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 mutexSystem.IO.Packaging and System.IO.Compression contain some useful content too.
BTW there's #ziplib, a .NET ZIP library.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement