C#和IStream.Read

Jef*_*rey 5 c# istream

我正在尝试使用C#中的System.Runtime.InteropServices.ComTypes.IStream,但我遇到了一些麻烦.根据MSDN,C#定义如下所示:

void Read(
    byte[] pv,
    int cb,
    IntPtr pcbRead
)
Run Code Online (Sandbox Code Playgroud)

基本上,我可以从流中读取数据,但上面的"pcbRead"值始终为"0"(即使字节数组包含我的数据).做一些阅读,似乎pcbRead参数设置得有点棘手(尽管我对C#还不熟悉).

无论如何,我的代码基本上是这样的:

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;
}
Run Code Online (Sandbox Code Playgroud)

同样,问题是"myPtr"在读取后仍然包含"0",尽管"缓冲区"似乎包含有效数据.

Han*_*ant 7

您应该传递该参数的指针.IStream :: Read()函数将写入实际读取到指向位置的字节数.这需要C#中的不安全代码,例如:

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;
}
Run Code Online (Sandbox Code Playgroud)

不使用unsafe关键字也可以这样做:

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);
}
Run Code Online (Sandbox Code Playgroud)

如果您偶尔使用此方法,则应使用Marshal.CoTaskMemFree()来释放内存.