C# IStream实现IStream

10

首先,这不是与此存在COM互操作IStream的包装类吗?重复的问题,因为我需要在另一个方向上进行实现。我需要从IO.Stream创建一个IStream实现到IStream。但在开始尝试之前,想问一下是否有任何已经存在的实现或相关文章。我在.net框架和谷歌中都找不到任何内容,只给我提供了从IStream到IO.Stream的实现结果。所以,有人能给我一个好的提示吗?我真的不知道该如何开始,因为第一个成员(Clone-创建一个新的流对象,引用相同字节作为原始流,但提供独立的寻求指针到这些字节)让我感到困扰。我不知道如何基于IO.Stream来实现它。

1个回答

6
最后,我已经自己完成了这个任务(随意复制和修改):
[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;
            }
        }
    }

COM客户端最终将在IUnknown COM接口/CCW上调用::Release(),但没有办法将其连接到.Dispose()? - toong
即使看起来可以工作,但不是按原样工作:System.IO.Stream.Read() 允许提前返回并告诉它没有读取所有字节,而只是一个或多个。IStream::Read() 总是 读取所有请求的字节,除非到达流的结尾。不同、不兼容的合同:您必须在实现 IStream.Read() 中添加读取循环,并读取/填充缓冲区,直到获得所有请求的字节或没有更多可读取的内容为止。 - Axel Rietschin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接