Skip to content

Instantly share code, notes, and snippets.

@egtra
Last active December 19, 2015 10:59
Show Gist options
  • Select an option

  • Save egtra/5943987 to your computer and use it in GitHub Desktop.

Select an option

Save egtra/5943987 to your computer and use it in GitHub Desktop.
COMのIStreamをラップするSystem.IO.Streamの実装例。
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