2013-07-29 31 views
8

Po pierwsze nie jest to duplikat tego Does a wrapper class for a COM interop IStream already exist?, ponieważ potrzebuję implementacji w innym kierunku. Potrzebuję utworzyć implementację IStream z IO.Stream do IStream. Ale zanim zacznę próbować to zrobić, chciałem zapytać, czy ktoś zna już istniejącą implementację lub jakiekolwiek artykuły na jej temat. Nie mogłem znaleźć niczego w strukturze .net i google właśnie podał mi wyniki implementacji od IStream do IO.Stream. Czy ktoś ma dla mnie fajną wskazówkę? Naprawdę nie wiem, jak zacząć, ponieważ pierwszy element (Clone -> Tworzy nowy obiekt strumienia, który odwołuje się do tych samych bajtów co oryginalny strumień, ale dostarcza oddzielny wskaźnik wyszukiwania do tych bajtów) sprawia mi kłopot. Nie mam pojęcia, jak to zrobić na podstawie IO.Stream.C# Implementacja IStream IStream

Odpowiedz

5

Wreszcie zrobiłem to sam (czuć swobodnie kopiować i modyfikować):

[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

klient COM zakończy się wzywającą :: Release() na IUnknown interfejsu COM/CCW, ale nie ma sposobu, aby podłączyć to do .Dispose()? – toong

+0

Nie działa tak, jak jest, nawet jeśli wydaje się, że: System.IO.Stream.Read() może powrócić wcześniej i powiedzieć, że nie przeczytał wszystkich bajtów, ale tylko jeden lub więcej. IStream :: Read() * always * czyta wszystkie żądane bajty, chyba że został osiągnięty koniec strumienia. Różne, niezgodne umowy: musisz dodać pętlę do odczytu w swojej implementacji IStream.Read() i odczytać/wypełnić bufor, dopóki nie otrzymasz wszystkich żądanych bajtów lub nie będzie więcej do przeczytania. –