C#和IStream.读

C#和IStream.读,c#,istream,C#,Istream,我正在尝试使用C#中的System.Runtime.InteropServices.ComTypes.IStream,但遇到了一些问题。根据MSDN,C#的定义如下: void Read( byte[] pv, int cb, IntPtr pcbRead ) myPtr = (IntPtr)0; int buffSize = 8192; byte[] buffer = new byte[buffSize]; while (true) { strm.Read(buf

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

void Read(
    byte[] pv,
    int cb,
    IntPtr pcbRead
)
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;
}
基本上,我可以从流中读取数据,但上面的“pcbRead”值始终为“0”(即使字节数组包含我的数据)。在阅读时,pcbRead参数似乎有点难以正确设置(尽管我对C#还是相当陌生)

总之,我的代码基本上如下所示:

void Read(
    byte[] pv,
    int cb,
    IntPtr pcbRead
)
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;
}
myPtr=(IntPtr)0;
int buffSize=8192;
字节[]缓冲区=新字节[buffSize];
while(true)
{
strm.Read(缓冲区、buffSize、myPtr);
写入(缓冲区,0,myPtr.ToInt32());
如果(myPtr.ToInt32()

同样,问题是“myPtr”在读取后仍然包含“0”,尽管“buffer”似乎包含有效数据。

我没有使用IStream的经验,但查看您的代码,我发现一些潜在错误。
变量myPtr在开始时设置为零。ItPtR像C++中的指针一样工作,所以我认为这个方法希望它把值写入MypTR点的位置。 你能试着这样做吗

unsafe 
{
    int pcbRead = 0;
    int buffSize = 8192;
    byte[] buffer = new byte[buffSize];
    while (true)
    {
        // taking address of pcbRead
        strm.Read(buffer, buffSize, new IntPtr(&pcbRead)); 
        fs.Write(buffer, 0, pcbRead);
        if (pcbRead < buffSize) break;
    }
}
不安全
{
int pcbRead=0;
int buffSize=8192;
字节[]缓冲区=新字节[buffSize];
while(true)
{
//获取pcbRead的地址
strm.Read(缓冲区、buffSize、新IntPtr(&pcbRead));
fs.写入(缓冲区,0,pcbRead);
如果(pcbRead
您应该为该参数传递一个指针。函数的作用是:将实际读取的字节数写入指向的位置。这需要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;
}
也可以在不使用不安全关键字的情况下执行此操作:

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);
}

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

以下是一个基于Hans答案的解决方案,它为您提供了一个类,您可以直接将其放入项目中。它为所有IStream对象提供扩展方法

这会将数据传输到.net内存流,但如果愿意,可以将其更改为文件

using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace YourProject
{
  public static class IStreamExtensions
  {
    private const int bufferSize = 8192;
    public static MemoryStream ReadToMemoryStream(this IStream comStream)
    {
      var memoryStream = new MemoryStream();

      var amtRead = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)));
      Marshal.WriteInt32(amtRead, bufferSize);
      var buffer = new byte[bufferSize];
      while (Marshal.ReadInt32(amtRead) > 0)
      {
        comStream.Read(buffer, buffer.Length, amtRead);
        memoryStream.Write(buffer, 0, Marshal.ReadInt32(amtRead));
      }
      memoryStream.Position = 0;

      return memoryStream;
    }
  }
}
用法:

IStream istream = (IStream) someCOMclass.giveMeAStream();
MemoryStream netStream = istream.ReadToMemoryStream();