【问题标题】:C# IStream implemenation of IStreamIStream 的 C# OStream 实现
【发布时间】:2013-07-29 10:35:40
【问题描述】:

首先,这与Does a wrapper class for a COM interop IStream already exist? 没有重复,因为我需要在另一个方向上实现。我需要创建一个从 IO.Stream 到 IStream 的 IStream 实现。但在我开始尝试这样做之前,想问一下是否有人知道已经存在的实现或任何关于它的文章。我在 .net 框架中找不到任何东西,谷歌只是给了我从 IStream 到 IO.Stream 的实现结果。那么有人对我有什么好的建议吗?我真的不知道如何开始,因为第一个成员(克隆 -> 创建一个新的流对象,它引用与原始流相同的字节,但提供指向这些字节的单独搜索指针)让我很麻烦。我不知道如何基于 IO.Stream 来做到这一点。

【问题讨论】:

    标签: c# stream wrapper istream


    【解决方案1】:

    最后,我自己完成了(随意复制和修改):

    [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-interface/CCW 上调用 ::Release(),但没有办法将其与 .Dispose() 挂钩?
    • 不能按原样工作,即使它看起来是:允许 System.IO.Stream.Read() 提前返回并告诉它没有读取所有字节,而只是一个或多个. IStream::Read() 总是 读取所有请求的字节,除非到达流的末尾。不同的、不兼容的合约:您必须在 IStream.Read() 的实现中添加一个读取循环并读取/填充缓冲区,直到您获得所有请求的字节,或者没有更多要读取的字节。
    猜你喜欢
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 2020-02-10
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多