I'm trying to use System.Runtime.InteropServices.ComTypes.IStream from C#, but I'm having some trouble. According to MSDN, the C# definition looks like this:
void Read(
byte[] pv,
int cb,
IntPtr pcbRead
)
Basically, I can read data from the stream, but the above "pcbRead" value is always "0" (even though the byte array contains my data). Doing some reading, it seems as if the pcbRead argument is somewhat tricky to set up properly (though I'm fairly new to C#).
Anyway, my code basically looks like this:
myPtr = (IntPtr)0;
int buffSize = 8192;
byte[] buffer = new byte[buffSize];
while (true)
{
strm.Read(buffer, buffSize, myPtr);
fs.Write(buffer, 0, myPtr.ToInt32());
if (myPtr.ToInt32() < buffSize) break;
}
Again, the problem is that "myPtr" still contains "0" after the read, though "buffer" seems to contain valid data.
You are supposed to pass a pointer for that argument. The IStream::Read() function will write the number of bytes that were actually read to the pointed-to location. This requires unsafe code in C#, for example:
unsafe static int Read(System.Runtime.InteropServices.ComTypes.IStream strm,
byte[] buffer) {
int bytesRead = 0;
int* ptr = &bytesRead;
strm.Read(buffer, buffer.Length, (IntPtr)ptr);
return bytesRead;
}
Doing it without the unsafe keyword is possible too:
private static IntPtr ReadBuffer;
static int Read(System.Runtime.InteropServices.ComTypes.IStream strm,
byte[] buffer) {
if (ReadBuffer == IntPtr.Zero) ReadBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)));
strm.Read(buffer, buffer.Length, ReadBuffer);
return Marshal.ReadInt32(ReadBuffer);
}
If you use this method only occasionally you ought to use Marshal.CoTaskMemFree() to release the memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With