using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
namespace ImportExport
{
#region ManagedIStream object
///
/// ManagedIStream wraps a .Net Stream object as a COM IStream interface
///
///
[Guid("0000000c-0000-0000-C000-000000000046"),
ClassInterface(ClassInterfaceType.None)]
public class ManagedIStream : IStream, IDisposable
{
public ManagedIStream(Stream stream)
{
if (stream == null) throw new ArgumentNullException("stream parameter cannot be null");
_stream = stream;
}
[SecurityCritical]
void IStream.Read(Byte[] buffer, Int32 bufferSize, IntPtr bytesReadPtr)
{
Int32 bytesRead = _stream.Read(buffer, 0, (int)bufferSize);
if (bytesReadPtr != IntPtr.Zero)
{
Marshal.WriteInt32(bytesReadPtr, bytesRead);
}
}
[SecurityCritical]
void IStream.Seek(Int64 offset, Int32 origin, IntPtr newPositionPtr)
{
SeekOrigin seekOrigin;
switch (origin)
{
case StreamConsts.STREAM_SEEK_SET:
seekOrigin = SeekOrigin.Begin;
break;
case StreamConsts.STREAM_SEEK_CUR:
seekOrigin = SeekOrigin.Current;
break;
case StreamConsts.STREAM_SEEK_END:
seekOrigin = SeekOrigin.End;
break;
default:
throw new ArgumentOutOfRangeException("origin parameter can only be STREAM_SEEK_SET / STREAM_SEEK_CUR / STREAM_SEEK_END");
}
long position = _stream.Seek(offset, seekOrigin);
if (newPositionPtr != IntPtr.Zero)
{
Marshal.WriteInt64(newPositionPtr, position);
}
}
void IStream.SetSize(Int64 libNewSize)
{
_stream.SetLength(libNewSize);
}
void IStream.Stat(out System.Runtime.InteropServices.ComTypes.STATSTG streamStats, int grfStatFlag)
{
streamStats = new System.Runtime.InteropServices.ComTypes.STATSTG();
streamStats.type = (int)STGTY.STGTY_STREAM;
streamStats.cbSize = _stream.Length;
streamStats.grfMode = 0; // default value
if (_stream.CanRead && _stream.CanWrite)
{
streamStats.grfMode |= (int)STGM.READWRITE;
}
else if (_stream.CanRead)
{
streamStats.grfMode |= (int)STGM.READ;
}
else if (_stream.CanWrite)
{
streamStats.grfMode |= (int)STGM.WRITE;
}
else
{
// A stream that is neither readable nor writable is a closed stream.
throw new IOException("Cannot access a closed stream");
}
}
[SecurityCritical]
void IStream.Write(Byte[] buffer, Int32 bufferSize, IntPtr bytesWrittenPtr)
{
_stream.Write(buffer, 0, bufferSize);
if (bytesWrittenPtr != IntPtr.Zero)
{
// If fewer than bufferSize bytes had been written, an exception would
// have been thrown, so it can be assumed we wrote bufferSize bytes.
Marshal.WriteInt32(bytesWrittenPtr, bufferSize);
}
}
public void Dispose()
{
_stream.Dispose();
_stream = null;
}
#region Unimplemented methods
void IStream.Clone(out IStream streamCopy)
{
streamCopy = null;
throw new NotSupportedException();
}
void IStream.CopyTo(IStream targetStream, Int64 bufferSize, IntPtr buffer, IntPtr bytesWrittenPtr)
{
throw new NotSupportedException();
}
void IStream.Commit(Int32 flags)
{
//do nothing
}
void IStream.LockRegion(Int64 offset, Int64 byteCount, Int32 lockType)
{
throw new NotSupportedException();
}
void IStream.Revert()
{
throw new NotSupportedException();
}
void IStream.UnlockRegion(Int64 offset, Int64 byteCount, Int32 lockType)
{
throw new NotSupportedException();
}
#endregion Unimplemented methods
#region Fields
protected Stream _stream;
#endregion Fields
}
#endregion ManagedIStream object
#region FileIStream object
///
/// FileIStream wraps a file as an IStream object
///
public class FileIStream : ManagedIStream
{
public FileIStream(string FileName, bool CreateNew, bool Writable)
: base(File.Open(FileName, CreateNew ? FileMode.Create : FileMode.Open, Writable ? FileAccess.ReadWrite : FileAccess.Read))
{
_stream.Position = 0;
}
}
#endregion FileIStream object
#region constants
public sealed class StreamConsts
{
public const int LOCK_WRITE = 0x1;
public const int LOCK_EXCLUSIVE = 0x2;
public const int LOCK_ONLYONCE = 0x4;
public const int STATFLAG_DEFAULT = 0x0;
public const int STATFLAG_NONAME = 0x1;
public const int STATFLAG_NOOPEN = 0x2;
public const int STGC_DEFAULT = 0x0;
public const int STGC_OVERWRITE = 0x1;
public const int STGC_ONLYIFCURRENT = 0x2;
public const int STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 0x4;
public const int STREAM_SEEK_SET = 0x0;
public const int STREAM_SEEK_CUR = 0x1;
public const int STREAM_SEEK_END = 0x2;
}
[Flags]
public enum STGM : int
{
DIRECT = 0x00000000,
TRANSACTED = 0x00010000,
SIMPLE = 0x08000000,
READ = 0x00000000,
WRITE = 0x00000001,
READWRITE = 0x00000002,
SHARE_DENY_NONE = 0x00000040,
SHARE_DENY_READ = 0x00000030,
SHARE_DENY_WRITE = 0x00000020,
SHARE_EXCLUSIVE = 0x00000010,
PRIORITY = 0x00040000,
DELETEONRELEASE = 0x04000000,
NOSCRATCH = 0x00100000,
CREATE = 0x00001000,
CONVERT = 0x00020000,
FAILIFTHERE = 0x00000000,
NOSNAPSHOT = 0x00200000,
DIRECT_SWMR = 0x00400000,
}
public enum STATFLAG : uint
{
STATFLAG_DEFAULT = 0,
STATFLAG_NONAME = 1,
STATFLAG_NOOPEN = 2
}
public enum STGTY : int
{
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4
}
#endregion constants
}