2013-07-29 17 views
8

Zunächst ist dies kein Duplikat von diesem Does a wrapper class for a COM interop IStream already exist?, weil ich die Implementierung in die andere Richtung brauche. Ich muss eine IStream-Implementierung von IO.Stream zu IStream erstellen. Aber bevor ich anfange, das zu tun, wollte ich fragen, ob jemand eine bereits existierende Implementierung oder irgendwelche Artikel darüber weiß. Ich konnte im .NET Framework nichts finden und google gab mir nur Ergebnisse von Implementierungen von IStream zu IO.Stream. Hat also jemand einen netten Tipp für mich? Ich weiß wirklich nicht, wie man startet, weil das erste Mitglied (Clone -> Erzeugt ein neues stream-Objekt, das auf die gleichen Bytes wie der ursprüngliche Stream verweist, aber einen separaten Suchzeiger auf diese Bytes liefert) Probleme macht. Ich habe keine Ahnung, wie man das auf Basis von IO.Stream macht.C# IStream Implementierung von IStream

Antwort

5

Schließlich habe ich es selbst getan (fühlen Sie sich frei, es zu kopieren und ändern):

[ComImport] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
[Guid("0000000c-0000-0000-C000-000000000046")] 
public interface IStream 
{ 
    [PreserveSig] 
    HResult Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] [Out] byte[] pv, int cb, IntPtr pcbRead); 

    [PreserveSig] 
    HResult Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten); 

    [PreserveSig] 
    HResult Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition); 

    [PreserveSig] 
    HResult SetSize(long libNewSize); 

    HResult CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten); 

    [PreserveSig] 
    HResult Commit(int grfCommitFlags); 

    [PreserveSig] 
    HResult Revert(); 

    [PreserveSig] 
    HResult LockRegion(long libOffset, long cb, int dwLockType); 

    [PreserveSig] 
    HResult UnlockRegion(long libOffset, long cb, int dwLockType); 

    [PreserveSig] 
    HResult Stat(out comtypes.STATSTG pstatstg, int grfStatFlag); 

    [PreserveSig] 
    HResult Clone(out IStream ppstm); 
} 

    /// <summary> 
    /// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms752876(v=vs.85).aspx 
    /// </summary> 
    public class ComStream : Stream, IStream 
    { 
     private Stream _stream; 

     public ComStream(Stream stream) 
      : this(stream, true) 
     { 
     } 

     internal ComStream(Stream stream, bool sync) 
     { 
      if (stream == null) 
       throw new ArgumentNullException("stream"); 

      if (sync) 
      { 
       stream = Stream.Synchronized(stream); 
      } 
      _stream = stream; 
     } 

     HResult IStream.Clone(out IStream ppstm) 
     { 
      //ComStream newstream = new ComStream(_stream, false); 
      //ppstm = newstream; 
      ppstm = null; 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.Commit(int grfCommitFlags) 
     { 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) 
     { 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.LockRegion(long libOffset, long cb, int dwLockType) 
     { 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.Read(byte[] pv, int cb, IntPtr pcbRead) 
     { 
      if (!CanRead) 
       throw new InvalidOperationException("Stream not readable"); 

      int read = Read(pv, 0, cb); 
      if (pcbRead != IntPtr.Zero) 
       Marshal.WriteInt64(pcbRead, read); 
      return HResult.S_OK; 
     } 

     HResult IStream.Revert() 
     { 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) 
     { 
      SeekOrigin origin = (SeekOrigin)dwOrigin; //hope that the SeekOrigin enumeration won't change 
      long pos = Seek(dlibMove, origin); 
      if (plibNewPosition != IntPtr.Zero) 
       Marshal.WriteInt64(plibNewPosition, pos); 
      return HResult.S_OK; 
     } 

     HResult IStream.SetSize(long libNewSize) 
     { 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.Stat(out comtypes.STATSTG pstatstg, int grfStatFlag) 
     { 
      pstatstg = new comtypes.STATSTG(); 
      pstatstg.cbSize = Length; 
      return HResult.S_OK; 
     } 

     HResult IStream.UnlockRegion(long libOffset, long cb, int dwLockType) 
     { 
      return HResult.E_NOTIMPL; 
     } 

     HResult IStream.Write(byte[] pv, int cb, IntPtr pcbWritten) 
     { 
      if (!CanWrite) 
       throw new InvalidOperationException("Stream is not writeable."); 

      Write(pv, 0, cb); 
      if (pcbWritten != null) 
       Marshal.WriteInt32(pcbWritten, cb); 
      return HResult.S_OK; 
     } 

     public override bool CanRead 
     { 
      get { return _stream.CanRead; } 
     } 

     public override bool CanSeek 
     { 
      get { return _stream.CanSeek; } 
     } 

     public override bool CanWrite 
     { 
      get { return _stream.CanWrite; } 
     } 

     public override void Flush() 
     { 
      _stream.Flush(); 
     } 

     public override long Length 
     { 
      get { return _stream.Length; } 
     } 

     public override long Position 
     { 
      get 
      { 
       return _stream.Position; 
      } 
      set 
      { 
       _stream.Position = value; 
      } 
     } 

     public override int Read(byte[] buffer, int offset, int count) 
     { 
      return _stream.Read(buffer, offset, count); 
     } 

     public override long Seek(long offset, SeekOrigin origin) 
     { 
      return _stream.Seek(offset, origin); 
     } 

     public override void SetLength(long value) 
     { 
      _stream.SetLength(value); 
     } 

     public override void Write(byte[] buffer, int offset, int count) 
     { 
      _stream.Write(buffer, offset, count); 
     } 

     protected override void Dispose(bool disposing) 
     { 
      if (_stream != null) 
      { 
       _stream.Dispose(); 
       _stream = null; 
      } 
     } 
    } 
+0

der COM-Client wird am Ende Aufruf :: Release() auf der IUnknown COM-Schnittstelle/CCW, aber es gibt keine Möglichkeit, das mit .Dispose() zu verbinden? – toong

+0

Funktioniert nicht wie es ist, auch wenn es so aussieht: System.IO.Stream.Read() darf früh zurückkehren und sagen, dass es nicht alle Bytes gelesen hat, sondern nur einen oder mehrere. IStream :: Read() * always * liest alle angeforderten Bytes, bis das Ende des Streams erreicht ist. Unterschiedliche, inkompatible Verträge: Sie müssen eine Leseschleife in Ihrer Implementierung von IStream.Read() hinzufügen und den Puffer lesen/füllen, bis Sie entweder alle angeforderten Bytes erhalten haben oder nicht mehr zu lesen sind. –

Verwandte Themen