C# - Buffer Corruption with Marshal.Copy() - c#

I am receiving an IntPtr and an int specifying the number of bytes it points to. The data can contain any characters including null, EOL, etc. When trying the following, the buffer is corrupted:
//buffer is the IntPtr
//count is the number of bytes in 'buffer'
byte[] test = new byte[count];
Marshal.Copy(buffer, test, 0, count);
IntPtr ptr = IntPtr.Zero;
ptr = Marshal.AllocCoTaskMem(count);
Marshal.Copy(test, 0, ptr, count);
I would assume 'buffer' and 'ptr' would be pointing to the same buffer blob in different memory locations but they don't (I am just copying the same data to another mem location AFAIK). However, 'ptr' seems to point to an arbitrary memory location as it contains string references to DLL modules.
Any ideas? Thanks!

Related

What is the correct method to read from a NetworkStream?

I'm developing a software that will constantly receive requests of various types and different lengths.
In particular, the length is the part that interest me because I don't know the length of the message that I will go to receive.
For the moment I wrote this code that goes to write the received bytes in a byte[] of a very large size, and then copies in a second byte[] only the length of the data.
//get the network stream
NetworkStream networkStream = tcpClient.GetStream();
//initialize an bytes array of size 5 MB
byte[] largeArray = new byte[5242880];
//write the bytes in the largeArray
//determines the length of the received message
int lenght = networkStream.Read(largeArray, 0, largeArray.Length);
//initialize an bytes array with the correct message length
byte[] messageArray = new byte[lenght];
//make a copy from the largeArray to the messageArray with the right lenght
Buffer.BlockCopy(largeArray, 0, messageArray, 0, messageArray.Length);
I wanted to know if this method can be corrected or are there better alternatives to receive messages of unknown lengths ?

How to pass unsafe pointer to FileStream in C#

I am trying to write images acquired from a webcam to a file via FileStream in C#. They are 16-bit monochrome so I cannot just write out the Bitmap object. I am using Marshal.Copy() in order to work around this as follows:
unsafe private void RecordingFrame()
{
Bitmap bm16;
BitmapData bmd;
Emgu.CV.Image<Gray, UInt16> currentFrame;
const int ORIGIN_X = 0;
const int ORIGIN_Y = 0;
// get image here and put it in bm16...
bmd = bm16.LockBits(new Rectangle(ORIGIN_X, ORIGIN_Y, bm16.Width, bm16.Height),
ImageLockMode.ReadOnly, bm16.PixelFormat);
var length = bmd.Stride * bmd.Height;
byte[] bytes = new byte[length];
Marshal.Copy(bmd.Scan0, bytes, 0, length);
fsVideoWriter.Write(bytes, 0, length);
bm16.UnlockBits(bmd);
}
Is this the best way to accomplish this? I wanted to simply pass the BitmapData's Scan0 member as a pointer to FileStream but I couldn't figure out how to do this so I copied the data into a byte buffer. This reduces performance slightly so if I can improve it to achieve a higher frame rate I'd like to do so.
You could create an UnmanagedMemoryStream from bmd.Scan0 and then call CopyTo(fsVideoWriter). But I'm not sure if this would be any faster than what you have now.

How can I compute two hashes without reading the same file twice?

I have a program which is going to be used on very large files (current test data is 250GB). I need to be able to calculate both MD5 and SHA1 hashes for these files. Currently my code drops the stream into MD5.Create().ComputeHash(Stream stream), and then the same for SHA1. These, as far as I can tell, read the file in 4096-byte blocks to a buffer internal to the hashing function, until the end of the stream.
The problem is, doing this one after the other takes a VERY long time! Is there any way I can take data into a buffer and provide the buffer to BOTH algorithms before reading a new block into the buffer?
Please explain thoroughly as I'm not an experienced coder.
Sure. You can call TransformBlock repeatedly, and then TransformFinalBlock at the end and then use Hash to get the final hash. So something like:
using (var md5 = MD5.Create()) // Or MD5Cng.Create
using (var sha1 = SHA1.Create()) // Or SHA1Cng.Create
using (var input = File.OpenRead("file.data"))
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length()) > 0)
{
md5.TransformBlock(buffer, 0, bytesRead, buffer, 0);
sha1.TransformBlock(buffer, 0, bytesRead, buffer, 0);
}
// We have to call TransformFinalBlock, but we don't have any
// more data - just provide 0 bytes.
md5.TransformFinalBlock(buffer, 0, 0, buffer, 0);
sha1.TransformFinalBlock(buffer, 0, 0, buffer, 0);
byte[] md5Hash = md5.Hash;
byte[] sha1Hash = sha1.Hash;
}
The MD5Cng.Create and SHA1Cng.Create calls will create wrappers around native implementations which are likely to be faster than the implementations returned by MD5.Create and SHA1.Create, but which will be a bit less portable (e.g. for PCLs).

getting a byte array from a pinned object

It is possible to get a pointer from a managed array
byte [] buffer = new byte[length + byteAlignment];
GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr ptr = bufferHandle.AddrOfPinnedObject();
is there any way to do the opposite. getting a byte array from a pinned object without copying?
Sure, that's what Marshal.Copy is for - there is no way (well, no way without copying of some variety) to otherwise get memory between the managed and unmanaged states...well, that's not 100% true, but I'm assuming you don't want to rely solely on Win32/C and p/invoke to copy memory around.
Marshal.Copy use would look like:
IntPtr addressOfThing = ....;
byte[] buffer = new byte[...];
Marshal.Copy(addressOfThing, buffer, 0, bufferSize);

How to store an IStream to a file via C#?

I'm working with a 3rd party component that returns an IStream object (System.Runtime.InteropServices.ComTypes.IStream). I need to take the data in that IStream and write it to a file. I've managed to get that done, but I'm not really happy with the code.
With "strm" being my IStream, here's my test code...
// access the structure containing statistical info about the stream
System.Runtime.InteropServices.ComTypes.STATSTG stat;
strm.Stat(out stat, 0);
System.IntPtr myPtr = (IntPtr)0;
// get the "cbSize" member from the stat structure
// this is the size (in bytes) of our stream.
int strmSize = (int)stat.cbSize; // *** DANGEROUS *** (long to int cast)
byte[] strmInfo = new byte[strmSize];
strm.Read(strmInfo, strmSize, myPtr);
string outFile = #"c:\test.db3";
File.WriteAllBytes(outFile, strmInfo);
At the very least, I don't like the long to int cast as commented above, but I wonder if there's not a better way to get the original stream length than the above? I'm somewhat new to C#, so thanks for any pointers.
You don't need to do that cast, as you can read data from IStream source in chunks.
// ...
System.IntPtr myPtr = (IntPtr)-1;
using (FileStream fs = new FileStream(#"c:\test.db3", FileMode.OpenOrCreate))
{
byte[] buffer = new byte[8192];
while (myPtr.ToInt32() > 0)
{
strm.Read(buffer, buffer.Length, myPtr);
fs.Write(buffer, 0, myPtr.ToInt32());
}
}
This way (if works) is more memory efficient, as it just uses a small memory block to transfer data between that streams.
System.Runtime.InteropServices.ComTypes.IStream is a wrapper for ISequentialStream.
From MSDN: http://msdn.microsoft.com/en-us/library/aa380011(VS.85).aspx
The actual number of bytes read can be
less than the number of bytes
requested if an error occurs or if the
end of the stream is reached during
the read operation. The number of
bytes returned should always be
compared to the number of bytes
requested. If the number of bytes
returned is less than the number of
bytes requested, it usually means the
Read method attempted to read past the
end of the stream.
This documentation says, that you can loop and read as long as pcbRead is less then cb.

Categories