// 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); } } }