// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Ole32
{
using System;
using System.Runtime.InteropServices;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
///
/// Specifies the access mode to use when opening, creating, or deleting a storage object.
///
internal enum StorageMode
{
///
/// Indicates that the object is read-only, meaning that modifications cannot be made.
///
Read = 0x0,
///
/// Enables you to save changes to the object, but does not permit access to its data.
///
Write = 0x1,
///
/// Enables access and modification of object data.
///
ReadWrite = 0x2,
///
/// Specifies that subsequent openings of the object are not denied read or write access.
///
ShareDenyNone = 0x40,
///
/// Prevents others from subsequently opening the object in Read mode.
///
ShareDenyRead = 0x30,
///
/// Prevents others from subsequently opening the object for Write or ReadWrite access.
///
ShareDenyWrite = 0x20,
///
/// Prevents others from subsequently opening the object in any mode.
///
ShareExclusive = 0x10,
///
/// Opens the storage object with exclusive access to the most recently committed version.
///
Priority = 0x40000,
///
/// Indicates that an existing storage object or stream should be removed before the new object replaces it.
///
Create = 0x1000,
}
///
/// Wrapper for the compound storage file APIs.
///
internal sealed class Storage : IDisposable
{
private bool disposed;
private IStorage storage;
///
/// Instantiate a new Storage.
///
/// The native storage interface.
private Storage(IStorage storage)
{
this.storage = storage;
}
///
/// Storage destructor.
///
~Storage()
{
this.Dispose();
}
///
/// The IEnumSTATSTG interface enumerates an array of STATSTG structures.
///
[ComImport, Guid("0000000d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumSTATSTG
{
///
/// Gets a specified number of STATSTG structures.
///
/// The number of STATSTG structures requested.
/// An array of STATSTG structures returned.
/// The number of STATSTG structures retrieved in the rgelt parameter.
/// The error code.
[PreserveSig]
uint Next(uint celt, [MarshalAs(UnmanagedType.LPArray), Out] STATSTG[] rgelt, out uint pceltFetched);
///
/// Skips a specified number of STATSTG structures in the enumeration sequence.
///
/// The number of STATSTG structures to skip.
void Skip(uint celt);
///
/// Resets the enumeration sequence to the beginning of the STATSTG structure array.
///
void Reset();
///
/// Creates a new enumerator that contains the same enumeration state as the current STATSTG structure enumerator.
///
/// The cloned IEnumSTATSTG interface.
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSTATSTG Clone();
}
///
/// The IStorage interface supports the creation and management of structured storage objects.
///
[ComImport, Guid("0000000b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IStorage
{
///
/// Creates and opens a stream object with the specified name contained in this storage object.
///
/// The name of the newly created stream.
/// Specifies the access mode to use when opening the newly created stream.
/// Reserved for future use; must be zero.
/// Reserved for future use; must be zero.
/// On return, pointer to the location of the new IStream interface pointer.
void CreateStream(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStream ppstm);
///
/// Opens an existing stream object within this storage object using the specified access permissions in grfMode.
///
/// The name of the stream to open.
/// Reserved for future use; must be NULL.
/// Specifies the access mode to be assigned to the open stream.
/// Reserved for future use; must be zero.
/// A pointer to IStream pointer variable that receives the interface pointer to the newly opened stream object.
void OpenStream(string pwcsName, IntPtr reserved1, uint grfMode, uint reserved2, out IStream ppstm);
///
/// Creates and opens a new storage object nested within this storage object with the specified name in the specified access mode.
///
/// The name of the newly created storage object.
/// A value that specifies the access mode to use when opening the newly created storage object.
/// Reserved for future use; must be zero.
/// Reserved for future use; must be zero.
/// A pointer, when successful, to the location of the IStorage pointer to the newly created storage object.
void CreateStorage(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStorage ppstg);
///
/// Opens an existing storage object with the specified name in the specified access mode.
///
/// The name of the storage object to open.
/// Must be NULL.
/// Specifies the access mode to use when opening the storage object.
/// Must be NULL.
/// Reserved for future use; must be zero.
/// When successful, pointer to the location of an IStorage pointer to the opened storage object.
void OpenStorage(string pwcsName, IStorage pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved, out IStorage ppstg);
///
/// Copies the entire contents of an open storage object to another storage object.
///
/// The number of elements in the array pointed to by rgiidExclude.
/// An array of interface identifiers (IIDs) that either the caller knows about and does not want
/// copied or that the storage object does not support, but whose state the caller will later explicitly copy.
/// A string name block (refer to SNB) that specifies a block of storage or stream objects that are not to be copied to the destination.
/// A pointer to the open storage object into which this storage object is to be copied.
void CopyTo(uint ciidExclude, IntPtr rgiidExclude, IntPtr snbExclude, IStorage pstgDest);
///
/// Copies or moves a substorage or stream from this storage object to another storage object.
///
/// The name of the element in this storage object to be moved or copied.
/// IStorage pointer to the destination storage object.
/// The new name for the element in its new storage object.
/// Specifies whether the operation should be a move (STGMOVE_MOVE) or a copy (STGMOVE_COPY).
void MoveElementTo(string pwcsName, IStorage pstgDest, string pwcsNewName, uint grfFlags);
///
/// Reflects changes for a transacted storage object to the parent level.
///
/// Controls how the changes are committed to the storage object.
void Commit(uint grfCommitFlags);
///
/// Discards all changes that have been made to the storage object since the last commit operation.
///
void Revert();
///
/// Returns an enumerator object that can be used to enumerate the storage and stream objects contained within this storage object.
///
/// Reserved for future use; must be zero.
/// Reserved for future use; must be NULL.
/// Reserved for future use; must be zero.
/// Pointer to IEnumSTATSTG* pointer variable that receives the interface pointer to the new enumerator object.
void EnumElements(uint reserved1, IntPtr reserved2, uint reserved3, out IEnumSTATSTG ppenum);
///
/// Removes the specified storage or stream from this storage object.
///
/// The name of the storage or stream to be removed.
void DestroyElement(string pwcsName);
///
/// Renames the specified storage or stream in this storage object.
///
/// The name of the substorage or stream to be changed.
/// The new name for the specified substorage or stream.
void RenameElement(string pwcsOldName, string pwcsNewName);
///
/// Sets the modification, access, and creation times of the indicated storage element, if supported by the underlying file system.
///
/// The name of the storage object element whose times are to be modified.
/// Either the new creation time for the element or NULL if the creation time is not to be modified.
/// Either the new access time for the element or NULL if the access time is not to be modified.
/// Either the new modification time for the element or NULL if the modification time is not to be modified.
void SetElementTimes(string pwcsName, FILETIME pctime, FILETIME patime, FILETIME pmtime);
///
/// Assigns the specified CLSID to this storage object.
///
/// The CLSID that is to be associated with the storage object.
void SetClass(Guid clsid);
///
/// Stores up to 32 bits of state information in this storage object.
///
/// Specifies the new values of the bits to set.
/// A binary mask indicating which bits in grfStateBits are significant in this call.
void SetStateBits(uint grfStateBits, uint grfMask);
///
/// Returns the STATSTG structure for this open storage object.
///
/// On return, pointer to a STATSTG structure where this method places information about the open storage object.
/// Specifies that some of the members in the STATSTG structure are not returned, thus saving a memory allocation operation.
void Stat(out STATSTG pstatstg, uint grfStatFlag);
}
///
/// The IStream interface lets you read and write data to stream objects.
///
[ComImport, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IStream
{
///
/// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.
///
/// A pointer to the buffer which the stream data is read into.
/// The number of bytes of data to read from the stream object.
/// A pointer to a ULONG variable that receives the actual number of bytes read from the stream object.
void Read([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbRead);
///
/// Writes a specified number of bytes into the stream object starting at the current seek pointer.
///
/// A pointer to the buffer that contains the data that is to be written to the stream.
/// The number of bytes of data to attempt to write into the stream.
/// A pointer to a ULONG variable where this method writes the actual number of bytes written to the stream object.
void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten);
///
/// Changes the seek pointer to a new location relative to the beginning of the stream, the end of the stream, or the current seek pointer.
///
/// The displacement to be added to the location indicated by the dwOrigin parameter.
/// The origin for the displacement specified in dlibMove.
/// A pointer to the location where this method writes the value of the new seek pointer from the beginning of the stream.
void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition);
///
/// Changes the size of the stream object.
///
/// Specifies the new size of the stream as a number of bytes.
void SetSize(long libNewSize);
///
/// Copies a specified number of bytes from the current seek pointer in the stream to the current seek pointer in another stream.
///
/// A pointer to the destination stream.
/// The number of bytes to copy from the source stream.
/// A pointer to the location where this method writes the actual number of bytes read from the source.
/// A pointer to the location where this method writes the actual number of bytes written to the destination.
void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
///
/// Ensures that any changes made to a stream object open in transacted mode are reflected in the parent storage object.
///
/// Controls how the changes for the stream object are committed.
void Commit(int grfCommitFlags);
///
/// Discards all changes that have been made to a transacted stream since the last call to IStream::Commit.
///
void Revert();
///
/// Restricts access to a specified range of bytes in the stream.
///
/// Integer that specifies the byte offset for the beginning of the range.
/// Integer that specifies the length of the range, in bytes, to be restricted.
/// Specifies the restrictions being requested on accessing the range.
void LockRegion(long libOffset, long cb, int dwLockType);
///
/// Removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.
///
/// Specifies the byte offset for the beginning of the range.
/// Specifies, in bytes, the length of the range to be restricted.
/// Specifies the access restrictions previously placed on the range.
void UnlockRegion(long libOffset, long cb, int dwLockType);
///
/// Retrieves the STATSTG structure for this stream.
///
/// Pointer to a STATSTG structure where this method places information about this stream object.
/// Specifies that this method does not return some of the members in the STATSTG structure, thus saving a memory allocation operation.
void Stat(out STATSTG pstatstg, int grfStatFlag);
///
/// Creates a new stream object that references the same bytes as the original stream but provides a separate seek pointer to those bytes.
///
/// When successful, pointer to the location of an IStream pointer to the new stream object.
void Clone(out IStream ppstm);
}
///
/// Creates a new compound file storage object.
///
/// The compound file being created.
/// Specifies the access mode to use when opening the new storage object.
/// The created Storage object.
public static Storage CreateDocFile(string storageFile, StorageMode mode)
{
IStorage storage = NativeMethods.StgCreateDocfile(storageFile, (uint)mode, 0);
return new Storage(storage);
}
///
/// Opens an existing root storage object in the file system.
///
/// The file that contains the storage object to open.
/// Specifies the access mode to use to open the storage object.
/// The created Storage object.
public static Storage Open(string storageFile, StorageMode mode)
{
IStorage storage = NativeMethods.StgOpenStorage(storageFile, IntPtr.Zero, (uint)mode, IntPtr.Zero, 0);
return new Storage(storage);
}
///
/// Copies the entire contents of this open storage object into another Storage object.
///
/// The destination Storage object.
public void CopyTo(Storage destinationStorage)
{
this.storage.CopyTo(0, IntPtr.Zero, IntPtr.Zero, destinationStorage.storage);
}
///
/// Opens an existing Storage object with the specified name according to the specified access mode.
///
/// The name of the Storage object.
/// The opened Storage object.
public Storage OpenStorage(string name)
{
IStorage subStorage;
this.storage.OpenStorage(name, null, (uint)(StorageMode.Read | StorageMode.ShareExclusive), IntPtr.Zero, 0, out subStorage);
return new Storage(subStorage);
}
///
/// Disposes the managed and unmanaged objects in this object.
///
public void Dispose()
{
if (!this.disposed)
{
Marshal.ReleaseComObject(this.storage);
this.disposed = true;
}
GC.SuppressFinalize(this);
}
///
/// The native methods.
///
private sealed class NativeMethods
{
///
/// Protect the constructor since this class only contains static methods.
///
private NativeMethods()
{
}
///
/// Creates a new compound file storage object.
///
/// The name for the compound file being created.
/// Specifies the access mode to use when opening the new storage object.
/// Reserved for future use; must be zero.
/// A pointer to the location of the IStorage pointer to the new storage object.
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern IStorage StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, uint grfMode, uint reserved);
///
/// Opens an existing root storage object in the file system.
///
/// The file that contains the storage object to open.
/// Most often NULL.
/// Specifies the access mode to use to open the storage object.
/// If not NULL, pointer to a block of elements in the storage to be excluded as the storage object is opened.
/// Indicates reserved for future use; must be zero.
/// A pointer to a IStorage* pointer variable that receives the interface pointer to the opened storage.
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern IStorage StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IntPtr pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved);
}
}
}