| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /*************************************************************************************
- Extended WPF Toolkit
- Copyright (C) 2007-2013 Xceed Software Inc.
- This program is provided to you under the terms of the Microsoft Public
- License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
- For more features, controls, and fast professional support,
- pick up the Plus Edition at http://xceed.com/wpf_toolkit
- Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
- ***********************************************************************************/
- /**************************************************************************\
- Copyright Microsoft Corporation. All Rights Reserved.
- \**************************************************************************/
- namespace Standard
- {
- using System;
- using System.Diagnostics.CodeAnalysis;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Runtime.InteropServices.ComTypes;
- // disambiguate with System.Runtime.InteropServices.STATSTG
- using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
- // All these methods return void. Does the standard marshaller convert them to HRESULTs?
- /// <summary>
- /// Wraps a managed stream instance into an interface pointer consumable by COM.
- /// </summary>
- internal sealed class ManagedIStream : IStream, IDisposable
- {
- private const int STGTY_STREAM = 2;
- private const int STGM_READWRITE = 2;
- private const int LOCK_EXCLUSIVE = 2;
- private Stream _source;
- /// <summary>
- /// Initializes a new instance of the ManagedIStream class with the specified managed Stream object.
- /// </summary>
- /// <param name="source">
- /// The stream that this IStream reference is wrapping.
- /// </param>
- public ManagedIStream(Stream source)
- {
- Verify.IsNotNull(source, "source");
- _source = source;
- }
- private void _Validate()
- {
- if (null == _source)
- {
- throw new ObjectDisposedException("this");
- }
- }
- // Comments are taken from MSDN IStream documentation.
- #region IStream Members
- /// <summary>
- /// Creates a new stream object with its own seek pointer that
- /// references the same bytes as the original stream.
- /// </summary>
- /// <param name="ppstm">
- /// When this method returns, contains the new stream object. This parameter is passed uninitialized.
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for IStream::Clone in the MSDN library.
- /// This class doesn't implement Clone. A COMException is thrown if it is used.
- /// </remarks>
- [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")]
- [Obsolete("The method is not implemented", true)]
- public void Clone(out IStream ppstm)
- {
- ppstm = null;
- HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented.");
- }
- /// <summary>
- /// Ensures that any changes made to a stream object that is open in transacted
- /// mode are reflected in the parent storage.
- /// </summary>
- /// <param name="grfCommitFlags">
- /// A value that controls how the changes for the stream object are committed.
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for IStream::Commit in the MSDN library.
- /// </remarks>
- public void Commit(int grfCommitFlags)
- {
- _Validate();
- _source.Flush();
- }
- /// <summary>
- /// Copies a specified number of bytes from the current seek pointer in the
- /// stream to the current seek pointer in another stream.
- /// </summary>
- /// <param name="pstm">
- /// A reference to the destination stream.
- /// </param>
- /// <param name="cb">
- /// The number of bytes to copy from the source stream.
- /// </param>
- /// <param name="pcbRead">
- /// On successful return, contains the actual number of bytes read from the source.
- /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written
- /// to this parameter on success.)
- /// </param>
- /// <param name="pcbWritten">
- /// On successful return, contains the actual number of bytes written to the destination.
- /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written
- /// to this parameter on success.)
- /// </param>
- [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")]
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
- {
- Verify.IsNotNull(pstm, "pstm");
- _Validate();
- // Reasonbly sized buffer, don't try to copy large streams in bulk.
- var buffer = new byte[4096];
- long cbWritten = 0;
- while (cbWritten < cb)
- {
- int cbRead = _source.Read(buffer, 0, buffer.Length);
- if (0 == cbRead)
- {
- break;
- }
- // COM documentation is a bit vague here whether NULL is valid for the third parameter.
- // Going to assume it is, as most implementations I've seen treat it as optional.
- // It's possible this will break on some IStream implementations.
- pstm.Write(buffer, cbRead, IntPtr.Zero);
- cbWritten += cbRead;
- }
- if (IntPtr.Zero != pcbRead)
- {
- Marshal.WriteInt64(pcbRead, cbWritten);
- }
- if (IntPtr.Zero != pcbWritten)
- {
- Marshal.WriteInt64(pcbWritten, cbWritten);
- }
- }
- /// <summary>
- /// Restricts access to a specified range of bytes in the stream.
- /// </summary>
- /// <param name="libOffset">
- /// The byte offset for the beginning of the range.
- /// </param>
- /// <param name="cb">
- /// The length of the range, in bytes, to restrict.
- /// </param>
- /// <param name="dwLockType">
- /// The requested restrictions on accessing the range.
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for IStream::LockRegion in the MSDN library.
- /// This class doesn't implement LockRegion. A COMException is thrown if it is used.
- /// </remarks>
- [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)]
- public void LockRegion(long libOffset, long cb, int dwLockType)
- {
- HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented.");
- }
- /// <summary>
- /// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.
- /// </summary>
- /// <param name="pv">
- /// When this method returns, contains the data read from the stream. This parameter is passed uninitialized.
- /// </param>
- /// <param name="cb">
- /// The number of bytes to read from the stream object.
- /// </param>
- /// <param name="pcbRead">
- /// A pointer to a ULONG variable that receives the actual number of bytes read from the stream object.
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for ISequentialStream::Read in the MSDN library.
- /// </remarks>
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public void Read(byte[] pv, int cb, IntPtr pcbRead)
- {
- _Validate();
- int cbRead = _source.Read(pv, 0, cb);
- if (IntPtr.Zero != pcbRead)
- {
- Marshal.WriteInt32(pcbRead, cbRead);
- }
- }
- /// <summary>
- /// Discards all changes that have been made to a transacted stream since the last Commit call.
- /// </summary>
- /// <remarks>
- /// This class doesn't implement Revert. A COMException is thrown if it is used.
- /// </remarks>
- [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)]
- public void Revert()
- {
- HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented.");
- }
- /// <summary>
- /// Changes the seek pointer to a new location relative to the beginning of the
- /// stream, to the end of the stream, or to the current seek pointer.
- /// </summary>
- /// <param name="dlibMove">
- /// The displacement to add to dwOrigin.
- /// </param>
- /// <param name="dwOrigin">
- /// The origin of the seek. The origin can be the beginning of the file, the current seek pointer, or the end of the file.
- /// </param>
- /// <param name="plibNewPosition">
- /// On successful return, contains the offset of the seek pointer from the beginning of the stream.
- /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written
- /// to this parameter on success.)
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for IStream::Seek in the MSDN library.
- /// </remarks>
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
- {
- _Validate();
- long position = _source.Seek(dlibMove, (SeekOrigin)dwOrigin);
- if (IntPtr.Zero != plibNewPosition)
- {
- Marshal.WriteInt64(plibNewPosition, position);
- }
- }
- /// <summary>
- /// Changes the size of the stream object.
- /// </summary>
- /// <param name="libNewSize">
- /// The new size of the stream as a number of bytes.
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for IStream::SetSize in the MSDN library.
- /// </remarks>
- public void SetSize(long libNewSize)
- {
- _Validate();
- _source.SetLength(libNewSize);
- }
- /// <summary>
- /// Retrieves the STATSTG structure for this stream.
- /// </summary>
- /// <param name="pstatstg">
- /// When this method returns, contains a STATSTG structure that describes this stream object.
- /// This parameter is passed uninitialized.
- /// </param>
- /// <param name="grfStatFlag">
- /// Members in the STATSTG structure that this method does not return, thus saving some memory allocation operations.
- /// </param>
- public void Stat(out STATSTG pstatstg, int grfStatFlag)
- {
- pstatstg = default(STATSTG);
- _Validate();
- pstatstg.type = STGTY_STREAM;
- pstatstg.cbSize = _source.Length;
- pstatstg.grfMode = STGM_READWRITE;
- pstatstg.grfLocksSupported = LOCK_EXCLUSIVE;
- }
- /// <summary>
- /// Removes the access restriction on a range of bytes previously restricted with the LockRegion method.
- /// </summary>
- /// <param name="libOffset">The byte offset for the beginning of the range.
- /// </param>
- /// <param name="cb">
- /// The length, in bytes, of the range to restrict.
- /// </param>
- /// <param name="dwLockType">
- /// The access restrictions previously placed on the range.
- /// </param>
- /// <remarks>
- /// For more information, see the existing documentation for IStream::UnlockRegion in the MSDN library.
- /// This class doesn't implement UnlockRegion. A COMException is thrown if it is used.
- /// </remarks>
- [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")]
- [Obsolete("The method is not implemented", true)]
- public void UnlockRegion(long libOffset, long cb, int dwLockType)
- {
- HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented.");
- }
- /// <summary>
- /// Writes a specified number of bytes into the stream object starting at the current seek pointer.
- /// </summary>
- /// <param name="pv">
- /// The buffer to write this stream to.
- /// </param>
- /// <param name="cb">
- /// The number of bytes to write to the stream.
- /// </param>
- /// <param name="pcbWritten">
- /// On successful return, contains the actual number of bytes written to the stream object.
- /// If the caller sets this pointer to null, this method does not provide the actual number
- /// of bytes written.
- /// </param>
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public void Write(byte[] pv, int cb, IntPtr pcbWritten)
- {
- _Validate();
- _source.Write(pv, 0, cb);
- if (IntPtr.Zero != pcbWritten)
- {
- Marshal.WriteInt32(pcbWritten, cb);
- }
- }
- #endregion
- #region IDisposable Members
- /// <summary>
- /// Releases resources controlled by this object.
- /// </summary>
- /// <remarks>
- /// Dispose can be called multiple times, but trying to use the object
- /// after it has been disposed will generally throw ObjectDisposedExceptions.
- /// </remarks>
- public void Dispose()
- {
- _source = null;
- }
- #endregion
- }
- }
|