Last active
December 19, 2015 10:59
-
-
Save egtra/5943987 to your computer and use it in GitHub Desktop.
COMのIStreamをラップするSystem.IO.Streamの実装例。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.IO; | |
| using System.Runtime.InteropServices; | |
| using System.Runtime.InteropServices.ComTypes; | |
| namespace Egtra | |
| { | |
| namespace Internal | |
| { | |
| [Guid("0000000c-0000-0000-C000-000000000046")] | |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | |
| internal interface IStream | |
| { | |
| IStream Clone(); | |
| void Commit(int grfCommitFlags); | |
| void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten); | |
| void LockRegion(long libOffset, long cb, int dwLockType); | |
| void Read(IntPtr pv, int cb, out int pcbRead); | |
| void Revert(); | |
| void Seek(long dlibMove, int dwOrigin, out long plibNewPosition); | |
| void SetSize(long libNewSize); | |
| void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, STATFLAG grfStatFlag); | |
| void UnlockRegion(long libOffset, long cb, int dwLockType); | |
| void Write(IntPtr pv, int cb, out int pcbWritten); | |
| } | |
| } | |
| class ComStream : Stream | |
| { | |
| public ComStream(IStream s) | |
| { | |
| if (s == null) | |
| { | |
| throw new ArgumentNullException("s"); | |
| } | |
| stream = (Internal.IStream)s; | |
| } | |
| public override bool CanRead { get { return true; } } | |
| public override bool CanSeek { get { return true; } } | |
| public override bool CanWrite { get { return true; } } | |
| public override void Flush() { /* Nothing to do */ } | |
| public override long Length | |
| { | |
| get | |
| { | |
| System.Runtime.InteropServices.ComTypes.STATSTG statstg; | |
| stream.Stat(out statstg, STATFLAG_NONAME); | |
| return statstg.cbSize; | |
| } | |
| } | |
| public override long Position | |
| { | |
| get | |
| { | |
| long pos; | |
| stream.Seek(0, STREAM_SEEK_CUR, out pos); | |
| return pos; | |
| } | |
| set | |
| { | |
| if (Position < 0) | |
| { | |
| throw new ArgumentOutOfRangeException(); | |
| } | |
| long newPos; | |
| stream.Seek(value, STREAM_SEEK_SET, out newPos); | |
| } | |
| } | |
| public unsafe override int Read(byte[] buffer, int offset, int count) | |
| { | |
| if (offset > buffer.Length) | |
| { | |
| throw new ArgumentOutOfRangeException("offset"); | |
| } | |
| if ((long)offset + count > buffer.LongLength) | |
| { | |
| throw new ArgumentOutOfRangeException("count"); | |
| } | |
| fixed (byte* p = buffer) | |
| { | |
| int read; | |
| stream.Read(new IntPtr(p + offset), count, out read); | |
| return read; | |
| } | |
| } | |
| public override long Seek(long offset, SeekOrigin origin) | |
| { | |
| long result; | |
| stream.Seek(offset, SeekOriginToStreamSeek(origin), out result); | |
| return result; | |
| } | |
| private int SeekOriginToStreamSeek(SeekOrigin origin) | |
| { | |
| switch (origin) | |
| { | |
| case SeekOrigin.Begin: return STREAM_SEEK_SET; | |
| case SeekOrigin.Current: return STREAM_SEEK_CUR; | |
| case SeekOrigin.End: return STREAM_SEEK_END; | |
| default: throw new ArgumentOutOfRangeException(); | |
| } | |
| } | |
| public override void SetLength(long value) | |
| { | |
| if (value < 0) | |
| { | |
| throw new ArgumentOutOfRangeException("value"); | |
| } | |
| stream.SetSize(value); | |
| } | |
| public unsafe override void Write(byte[] buffer, int offset, int count) | |
| { | |
| if (offset > buffer.Length) | |
| { | |
| throw new ArgumentOutOfRangeException("offset"); | |
| } | |
| if ((long)offset + count > buffer.LongLength) | |
| { | |
| throw new ArgumentOutOfRangeException("count"); | |
| } | |
| fixed (byte* p = buffer) | |
| { | |
| int written; | |
| stream.Write(new IntPtr(p + offset), count, out written); | |
| if (written < count) | |
| { | |
| Write(buffer, written, count - written); | |
| } | |
| } | |
| } | |
| public IStream BaseStream { get { return (IStream)stream; } } | |
| private readonly Internal.IStream stream; | |
| private const int STREAM_SEEK_SET = 0; | |
| private const int STREAM_SEEK_CUR = 1; | |
| private const int STREAM_SEEK_END = 2; | |
| private const int STATFLAG_NONAME = 1; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment