Question

Je suis en train d'utiliser System.Runtime.InteropServices.ComTypes.IStream de C #, mais je vais avoir des ennuis. Selon MSDN, la définition C # ressemble à ceci:

void Read(
    byte[] pv,
    int cb,
    IntPtr pcbRead
)

En fait, je peux lire les données du flux, mais la valeur « pcbRead » ci-dessus est toujours « 0 » (même si le tableau d'octets contient mes données). Faire un peu de lecture, il semble que l'argument pcbRead est un peu difficile à mettre en place correctement (même si je suis assez nouveau pour C #).

De toute façon, mon code ressemble fondamentalement à ceci:

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

Encore une fois, le problème est que « myPtr » contient toujours « 0 » après la lecture, bien que « tampon » semble contenir des données valides.

Était-ce utile?

La solution

Vous êtes censé passer un pointeur pour cet argument. La fonction IStream :: Read () rédigera le nombre d'octets qui ont été effectivement lu au pointé à l'emplacement. Cela nécessite un code dangereux en C #, par exemple:

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

Le faire sans le mot clé unsafe est possible aussi:

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

Si vous utilisez cette méthode que de temps en temps vous devez utiliser Marshal.CoTaskMemFree () pour libérer la mémoire.

Autres conseils

Voici une solution qui construit au large de la réponse de Hans pour vous donner une classe, vous pouvez simplement laisser tomber dans votre projet. Il fournit une méthode d'extension pour tous les objets IStream.

Cela transférer les données à un flux de mémoire .net, mais vous pouvez changer cela pour être un fichier si vous préférez.

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

utilisation:

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

Je ne suis pas expérimenté avec IStream, mais en regardant votre code, je vois une erreur potentielle.
myPtr variable est mis à zéro au début. IntPtr fonctionne comme des pointeurs en C ++, donc je pense que cette méthode prévoit que d'écrire la valeur dans l'emplacement qui myPtr points.

Pouvez-vous essayer de le faire?

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;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top