From b8c0ce3f0f79b87015f810777828afd53bb9c9b4 Mon Sep 17 00:00:00 2001 From: dahall Date: Wed, 15 Jul 2020 15:03:26 -0600 Subject: [PATCH] Pulled classes and enums out of ShellFileOperations.cs into thier own files. --- .../ShellFileOperations.Enums.cs | 205 ++++++++++ .../ShellFileOperations.EventArgs.cs | 74 ++++ .../ShellFileOperations/ShellFileOperations.cs | 444 +-------------------- .../ShellItemPropertyUpdates.cs | 191 +++++++++ 4 files changed, 471 insertions(+), 443 deletions(-) create mode 100644 Windows.Shell/ShellFileOperations/ShellFileOperations.Enums.cs create mode 100644 Windows.Shell/ShellFileOperations/ShellFileOperations.EventArgs.cs create mode 100644 Windows.Shell/ShellFileOperations/ShellItemPropertyUpdates.cs diff --git a/Windows.Shell/ShellFileOperations/ShellFileOperations.Enums.cs b/Windows.Shell/ShellFileOperations/ShellFileOperations.Enums.cs new file mode 100644 index 00000000..3f0068e6 --- /dev/null +++ b/Windows.Shell/ShellFileOperations/ShellFileOperations.Enums.cs @@ -0,0 +1,205 @@ +using System; +using static Vanara.PInvoke.Shell32; + +namespace Vanara.Windows.Shell +{ + public partial class ShellFileOperations + { + /// Flags that control the file operation. + [Flags] + public enum OperationFlags : uint + { + /// + /// The pTo member specifies multiple destination files (one for each source file in pFrom) rather than one directory where all + /// source files are to be deposited. + /// + MultiDestFiles = FILEOP_FLAGS.FOF_MULTIDESTFILES, + + /// Do not display a progress dialog box. + Silent = FILEOP_FLAGS.FOF_SILENT, + + /// + /// Give the item being operated on a new name in a move, copy, or rename operation if an item with the target name already exists. + /// + RenameOnCollision = FILEOP_FLAGS.FOF_RENAMEONCOLLISION, + + /// Respond with Yes to All for any dialog box that is displayed. + NoConfirmation = FILEOP_FLAGS.FOF_NOCONFIRMATION, + + /// + /// If FOF_RENAMEONCOLLISION is specified and any files were renamed, assign a name mapping object that contains their old and + /// new names to the hNameMappings member. This object must be freed using SHFreeNameMappings when it is no longer needed. + /// + WantMappingHandle = FILEOP_FLAGS.FOF_WANTMAPPINGHANDLE, + + /// + /// Preserve undo information, if possible. + /// Prior to Windows Vista, operations could be undone only from the same process that performed the original operation. + /// + /// In Windows Vista and later systems, the scope of the undo is a user session. Any process running in the user session can + /// undo another operation. The undo state is held in the Explorer.exe process, and as long as that process is running, it can + /// coordinate the undo functions. + /// + /// If the source file parameter does not contain fully qualified path and file names, this flag is ignored. + /// + AllowUndo = FILEOP_FLAGS.FOF_ALLOWUNDO, + + /// Perform the operation only on files (not on folders) if a wildcard file name (*.*) is specified. + FilesOnly = FILEOP_FLAGS.FOF_FILESONLY, + + /// Display a progress dialog box but do not show individual file names as they are operated on. + SimpleProgress = FILEOP_FLAGS.FOF_SIMPLEPROGRESS, + + /// Do not confirm the creation of a new folder if the operation requires one to be created. + NoConfirmMkDir = FILEOP_FLAGS.FOF_NOCONFIRMMKDIR, + + /// + /// Do not display a message to the user if an error occurs. If this flag is set without FOFX_EARLYFAILURE, any error is treated + /// as if the user had chosen Ignore or Continue in a dialog box. It halts the current action, sets a flag to indicate that an + /// action was aborted, and proceeds with the rest of the operation. + /// + NoErrorUI = FILEOP_FLAGS.FOF_NOERRORUI, + + /// Do not copy the security attributes of the item. + NoCopySecurityAttribs = FILEOP_FLAGS.FOF_NOCOPYSECURITYATTRIBS, + + /// Only operate in the local folder. Do not operate recursively into subdirectories. + NoRecursion = FILEOP_FLAGS.FOF_NORECURSION, + + /// Do not move connected items as a group. Only move the specified files. + NoConnectedElements = FILEOP_FLAGS.FOF_NO_CONNECTED_ELEMENTS, + + /// + /// Send a warning if a file or folder is being destroyed during a delete operation rather than recycled. This flag partially + /// overrides FOF_NOCONFIRMATION. + /// + WantNukeWarning = FILEOP_FLAGS.FOF_WANTNUKEWARNING, + + /// Don't display any UI at all. + NoUI = FILEOP_FLAGS.FOF_NO_UI, + + /// + /// Walk into Shell namespace junctions. By default, junctions are not entered. For more information on junctions, see + /// Specifying a Namespace Extension's Location. + /// + NoSkipJunctions = FILEOP_FLAGS.FOFX_NOSKIPJUNCTIONS, + + /// If possible, create a hard link rather than a new instance of the file in the destination. + PreferHardLink = FILEOP_FLAGS.FOFX_PREFERHARDLINK, + + /// + /// If an operation requires elevated rights and the FOF_NOERRORUI flag is set to disable error UI, display a UAC UI prompt nonetheless. + /// + ShowElevationPrompt = FILEOP_FLAGS.FOFX_SHOWELEVATIONPROMPT, + + /// + /// Introduced in Windows 8. When a file is deleted, send it to the Recycle Bin rather than permanently deleting it. + /// + RecycleOnDelete = FILEOP_FLAGS.FOFX_RECYCLEONDELETE, + + /// + /// If FOFX_EARLYFAILURE is set together with FOF_NOERRORUI, the entire set of operations is stopped upon encountering any error + /// in any operation. This flag is valid only when FOF_NOERRORUI is set. + /// + EarlyFailure = FILEOP_FLAGS.FOFX_EARLYFAILURE, + + /// + /// Rename collisions in such a way as to preserve file name extensions. This flag is valid only when FOF_RENAMEONCOLLISION is + /// also set. + /// + PreserveFileExtensions = FILEOP_FLAGS.FOFX_PRESERVEFILEEXTENSIONS, + + /// + /// Keep the newer file or folder, based on the Date Modified property, if a collision occurs. This is done automatically with + /// no prompt UI presented to the user. + /// + KeepNewerFile = FILEOP_FLAGS.FOFX_KEEPNEWERFILE, + + /// Do not use copy hooks. + NoCopyHooks = FILEOP_FLAGS.FOFX_NOCOPYHOOKS, + + /// Do not allow the progress dialog to be minimized. + NoMinimizeBox = FILEOP_FLAGS.FOFX_NOMINIMIZEBOX, + + /// + /// Copy the security attributes of the source item to the destination item when performing a cross-volume move operation. + /// Without this flag, the destination item receives the security attributes of its new folder. + /// + MoveACLsAcrossVolumes = FILEOP_FLAGS.FOFX_MOVEACLSACROSSVOLUMES, + + /// Do not display the path of the source item in the progress dialog. + DontDisplaySourcePath = FILEOP_FLAGS.FOFX_DONTDISPLAYSOURCEPATH, + + /// Do not display the path of the destination item in the progress dialog. + DontDisplayDestPath = FILEOP_FLAGS.FOFX_DONTDISPLAYDESTPATH, + + /// + /// Introduced in Windows Vista SP1. The user expects a requirement for rights elevation, so do not display a dialog box asking + /// for a confirmation of the elevation. + /// + RequireElevation = FILEOP_FLAGS.FOFX_REQUIREELEVATION, + + /// + /// Introduced in Windows 8. The file operation was user-invoked and should be placed on the undo stack. This flag is preferred + /// to FOF_ALLOWUNDO. + /// + AddUndoRecord = FILEOP_FLAGS.FOFX_ADDUNDORECORD, + + /// Introduced in Windows 7. Display a Downloading instead of Copying message in the progress dialog. + CopyAsDownload = FILEOP_FLAGS.FOFX_COPYASDOWNLOAD, + + /// Introduced in Windows 7. Do not display the location line in the progress dialog. + DontDisplayLocations = FILEOP_FLAGS.FOFX_DONTDISPLAYLOCATIONS, + } + + /// Used by methods of the ITransferSource and ITransferDestination interfaces to control their file operations. + [Flags] + public enum TransferFlags + { + /// Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior. + Normal = TRANSFER_SOURCE_FLAGS.TSF_NORMAL, + + /// Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior + FailExist = TRANSFER_SOURCE_FLAGS.TSF_FAIL_EXIST, + + /// Rename with auto-name generation if the destination already exists. + RenameExist = TRANSFER_SOURCE_FLAGS.TSF_RENAME_EXIST, + + /// Overwrite or merge with the destination. + OverwriteExist = TRANSFER_SOURCE_FLAGS.TSF_OVERWRITE_EXIST, + + /// Allow creation of a decrypted destination. + AllowDecryption = TRANSFER_SOURCE_FLAGS.TSF_ALLOW_DECRYPTION, + + /// No discretionary access control list (DACL), system access control list (SACL), or owner. + NoSecurity = TRANSFER_SOURCE_FLAGS.TSF_NO_SECURITY, + + /// + /// Copy the creation time as part of the copy. This can be useful for a move operation that is being used as a copy and delete + /// operation (TSF_MOVE_AS_COPY_DELETE). + /// + CopyCreationTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_CREATION_TIME, + + /// Copy the last write time as part of the copy. + CopyWriteTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_WRITE_TIME, + + /// Assign write, read, and delete permissions as share mode. + UseFullAccess = TRANSFER_SOURCE_FLAGS.TSF_USE_FULL_ACCESS, + + /// Recycle on file delete, if possible. + DeleteRecycleIfPossible = TRANSFER_SOURCE_FLAGS.TSF_DELETE_RECYCLE_IF_POSSIBLE, + + /// Hard link to the desired source (not required). This avoids a normal copy operation. + CopyHardLink = TRANSFER_SOURCE_FLAGS.TSF_COPY_HARD_LINK, + + /// Copy the localized name. + CopyLocalizedName = TRANSFER_SOURCE_FLAGS.TSF_COPY_LOCALIZED_NAME, + + /// Move as a copy and delete operation. + MoveAsCopyDelete = TRANSFER_SOURCE_FLAGS.TSF_MOVE_AS_COPY_DELETE, + + /// Suspend Shell events. + SuspendShellEvents = TRANSFER_SOURCE_FLAGS.TSF_SUSPEND_SHELLEVENTS, + } + } +} \ No newline at end of file diff --git a/Windows.Shell/ShellFileOperations/ShellFileOperations.EventArgs.cs b/Windows.Shell/ShellFileOperations/ShellFileOperations.EventArgs.cs new file mode 100644 index 00000000..97d327a5 --- /dev/null +++ b/Windows.Shell/ShellFileOperations/ShellFileOperations.EventArgs.cs @@ -0,0 +1,74 @@ +using System; +using Vanara.PInvoke; +using static Vanara.PInvoke.Shell32; + +namespace Vanara.Windows.Shell +{ + public partial class ShellFileOperations + { + /// Arguments supplied to the event. + /// + public class ShellFileNewOpEventArgs : ShellFileOpEventArgs + { + internal ShellFileNewOpEventArgs(TRANSFER_SOURCE_FLAGS flags, IShellItem source, IShellItem folder, IShellItem dest, string name, HRESULT hr, string templ, uint attr) : + base(flags, source, folder, dest, name, hr) + { + TemplateName = templ; + FileAttributes = (System.IO.FileAttributes)attr; + } + + /// Gets the name of the template. + /// The name of the template. + public string TemplateName { get; protected set; } + + /// Gets the file attributes. + /// The file attributes. + public System.IO.FileAttributes FileAttributes { get; protected set; } + } + + /// + /// Arguments supplied to events from . Depending on the event, some properties may not be set. + /// + /// + public class ShellFileOpEventArgs : EventArgs + { + internal ShellFileOpEventArgs(TRANSFER_SOURCE_FLAGS flags, IShellItem source, IShellItem folder = null, IShellItem dest = null, string name = null, HRESULT hr = default) + { + Flags = (TransferFlags)flags; + if (source != null) SourceItem = ShellItem.Open(source); + if (folder != null) DestFolder = ShellItem.Open(folder); + if (dest != null) DestItem = ShellItem.Open(dest); + Name = name; + Result = hr; + } + + /// Gets the destination folder. + /// The destination folder. + public ShellItem DestFolder { get; protected set; } + + /// Gets the destination item. + /// The destination item. + public ShellItem DestItem { get; protected set; } + + /// Gets the tranfer flag values. + /// The flags. + public TransferFlags Flags { get; protected set; } + + /// Gets the name of the item. + /// The item name. + public string Name { get; protected set; } + + /// Gets the result of the operation. + /// The result. + public HRESULT Result { get; protected set; } + + /// Gets the source item. + /// The source item. + public ShellItem SourceItem { get; protected set; } + + /// Returns a that represents this instance. + /// A that represents this instance. + public override string ToString() => $"HR:{Result};Src:{SourceItem};DFld:{DestFolder};Dst:{DestItem};Name:{Name}"; + } + } +} \ No newline at end of file diff --git a/Windows.Shell/ShellFileOperations/ShellFileOperations.cs b/Windows.Shell/ShellFileOperations/ShellFileOperations.cs index ca4f1839..748a0891 100644 --- a/Windows.Shell/ShellFileOperations/ShellFileOperations.cs +++ b/Windows.Shell/ShellFileOperations/ShellFileOperations.cs @@ -14,7 +14,7 @@ namespace Vanara.Windows.Shell { /// Queued and static file operations using the Shell. /// - public class ShellFileOperations : IDisposable + public partial class ShellFileOperations : IDisposable { private const OperationFlags defaultOptions = OperationFlags.AllowUndo | OperationFlags.NoConfirmMkDir; private bool disposedValue = false; @@ -79,203 +79,6 @@ namespace Vanara.Windows.Shell /// Occurs when a progress update is received. public event System.ComponentModel.ProgressChangedEventHandler UpdateProgress; - /// Flags that control the file operation. - [Flags] - public enum OperationFlags : uint - { - /// - /// The pTo member specifies multiple destination files (one for each source file in pFrom) rather than one directory where all - /// source files are to be deposited. - /// - MultiDestFiles = FILEOP_FLAGS.FOF_MULTIDESTFILES, - - /// Do not display a progress dialog box. - Silent = FILEOP_FLAGS.FOF_SILENT, - - /// - /// Give the item being operated on a new name in a move, copy, or rename operation if an item with the target name already exists. - /// - RenameOnCollision = FILEOP_FLAGS.FOF_RENAMEONCOLLISION, - - /// Respond with Yes to All for any dialog box that is displayed. - NoConfirmation = FILEOP_FLAGS.FOF_NOCONFIRMATION, - - /// - /// If FOF_RENAMEONCOLLISION is specified and any files were renamed, assign a name mapping object that contains their old and - /// new names to the hNameMappings member. This object must be freed using SHFreeNameMappings when it is no longer needed. - /// - WantMappingHandle = FILEOP_FLAGS.FOF_WANTMAPPINGHANDLE, - - /// - /// Preserve undo information, if possible. - /// Prior to Windows Vista, operations could be undone only from the same process that performed the original operation. - /// - /// In Windows Vista and later systems, the scope of the undo is a user session. Any process running in the user session can - /// undo another operation. The undo state is held in the Explorer.exe process, and as long as that process is running, it can - /// coordinate the undo functions. - /// - /// If the source file parameter does not contain fully qualified path and file names, this flag is ignored. - /// - AllowUndo = FILEOP_FLAGS.FOF_ALLOWUNDO, - - /// Perform the operation only on files (not on folders) if a wildcard file name (*.*) is specified. - FilesOnly = FILEOP_FLAGS.FOF_FILESONLY, - - /// Display a progress dialog box but do not show individual file names as they are operated on. - SimpleProgress = FILEOP_FLAGS.FOF_SIMPLEPROGRESS, - - /// Do not confirm the creation of a new folder if the operation requires one to be created. - NoConfirmMkDir = FILEOP_FLAGS.FOF_NOCONFIRMMKDIR, - - /// - /// Do not display a message to the user if an error occurs. If this flag is set without FOFX_EARLYFAILURE, any error is treated - /// as if the user had chosen Ignore or Continue in a dialog box. It halts the current action, sets a flag to indicate that an - /// action was aborted, and proceeds with the rest of the operation. - /// - NoErrorUI = FILEOP_FLAGS.FOF_NOERRORUI, - - /// Do not copy the security attributes of the item. - NoCopySecurityAttribs = FILEOP_FLAGS.FOF_NOCOPYSECURITYATTRIBS, - - /// Only operate in the local folder. Do not operate recursively into subdirectories. - NoRecursion = FILEOP_FLAGS.FOF_NORECURSION, - - /// Do not move connected items as a group. Only move the specified files. - NoConnectedElements = FILEOP_FLAGS.FOF_NO_CONNECTED_ELEMENTS, - - /// - /// Send a warning if a file or folder is being destroyed during a delete operation rather than recycled. This flag partially - /// overrides FOF_NOCONFIRMATION. - /// - WantNukeWarning = FILEOP_FLAGS.FOF_WANTNUKEWARNING, - - /// Don't display any UI at all. - NoUI = FILEOP_FLAGS.FOF_NO_UI, - - /// - /// Walk into Shell namespace junctions. By default, junctions are not entered. For more information on junctions, see - /// Specifying a Namespace Extension's Location. - /// - NoSkipJunctions = FILEOP_FLAGS.FOFX_NOSKIPJUNCTIONS, - - /// If possible, create a hard link rather than a new instance of the file in the destination. - PreferHardLink = FILEOP_FLAGS.FOFX_PREFERHARDLINK, - - /// - /// If an operation requires elevated rights and the FOF_NOERRORUI flag is set to disable error UI, display a UAC UI prompt nonetheless. - /// - ShowElevationPrompt = FILEOP_FLAGS.FOFX_SHOWELEVATIONPROMPT, - - /// - /// Introduced in Windows 8. When a file is deleted, send it to the Recycle Bin rather than permanently deleting it. - /// - RecycleOnDelete = FILEOP_FLAGS.FOFX_RECYCLEONDELETE, - - /// - /// If FOFX_EARLYFAILURE is set together with FOF_NOERRORUI, the entire set of operations is stopped upon encountering any error - /// in any operation. This flag is valid only when FOF_NOERRORUI is set. - /// - EarlyFailure = FILEOP_FLAGS.FOFX_EARLYFAILURE, - - /// - /// Rename collisions in such a way as to preserve file name extensions. This flag is valid only when FOF_RENAMEONCOLLISION is - /// also set. - /// - PreserveFileExtensions = FILEOP_FLAGS.FOFX_PRESERVEFILEEXTENSIONS, - - /// - /// Keep the newer file or folder, based on the Date Modified property, if a collision occurs. This is done automatically with - /// no prompt UI presented to the user. - /// - KeepNewerFile = FILEOP_FLAGS.FOFX_KEEPNEWERFILE, - - /// Do not use copy hooks. - NoCopyHooks = FILEOP_FLAGS.FOFX_NOCOPYHOOKS, - - /// Do not allow the progress dialog to be minimized. - NoMinimizeBox = FILEOP_FLAGS.FOFX_NOMINIMIZEBOX, - - /// - /// Copy the security attributes of the source item to the destination item when performing a cross-volume move operation. - /// Without this flag, the destination item receives the security attributes of its new folder. - /// - MoveACLsAcrossVolumes = FILEOP_FLAGS.FOFX_MOVEACLSACROSSVOLUMES, - - /// Do not display the path of the source item in the progress dialog. - DontDisplaySourcePath = FILEOP_FLAGS.FOFX_DONTDISPLAYSOURCEPATH, - - /// Do not display the path of the destination item in the progress dialog. - DontDisplayDestPath = FILEOP_FLAGS.FOFX_DONTDISPLAYDESTPATH, - - /// - /// Introduced in Windows Vista SP1. The user expects a requirement for rights elevation, so do not display a dialog box asking - /// for a confirmation of the elevation. - /// - RequireElevation = FILEOP_FLAGS.FOFX_REQUIREELEVATION, - - /// - /// Introduced in Windows 8. The file operation was user-invoked and should be placed on the undo stack. This flag is preferred - /// to FOF_ALLOWUNDO. - /// - AddUndoRecord = FILEOP_FLAGS.FOFX_ADDUNDORECORD, - - /// Introduced in Windows 7. Display a Downloading instead of Copying message in the progress dialog. - CopyAsDownload = FILEOP_FLAGS.FOFX_COPYASDOWNLOAD, - - /// Introduced in Windows 7. Do not display the location line in the progress dialog. - DontDisplayLocations = FILEOP_FLAGS.FOFX_DONTDISPLAYLOCATIONS, - } - - /// Used by methods of the ITransferSource and ITransferDestination interfaces to control their file operations. - [Flags] - public enum TransferFlags - { - /// Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior. - Normal = TRANSFER_SOURCE_FLAGS.TSF_NORMAL, - - /// Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior - FailExist = TRANSFER_SOURCE_FLAGS.TSF_FAIL_EXIST, - - /// Rename with auto-name generation if the destination already exists. - RenameExist = TRANSFER_SOURCE_FLAGS.TSF_RENAME_EXIST, - - /// Overwrite or merge with the destination. - OverwriteExist = TRANSFER_SOURCE_FLAGS.TSF_OVERWRITE_EXIST, - - /// Allow creation of a decrypted destination. - AllowDecryption = TRANSFER_SOURCE_FLAGS.TSF_ALLOW_DECRYPTION, - - /// No discretionary access control list (DACL), system access control list (SACL), or owner. - NoSecurity = TRANSFER_SOURCE_FLAGS.TSF_NO_SECURITY, - - /// - /// Copy the creation time as part of the copy. This can be useful for a move operation that is being used as a copy and delete - /// operation (TSF_MOVE_AS_COPY_DELETE). - /// - CopyCreationTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_CREATION_TIME, - - /// Copy the last write time as part of the copy. - CopyWriteTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_WRITE_TIME, - - /// Assign write, read, and delete permissions as share mode. - UseFullAccess = TRANSFER_SOURCE_FLAGS.TSF_USE_FULL_ACCESS, - - /// Recycle on file delete, if possible. - DeleteRecycleIfPossible = TRANSFER_SOURCE_FLAGS.TSF_DELETE_RECYCLE_IF_POSSIBLE, - - /// Hard link to the desired source (not required). This avoids a normal copy operation. - CopyHardLink = TRANSFER_SOURCE_FLAGS.TSF_COPY_HARD_LINK, - - /// Copy the localized name. - CopyLocalizedName = TRANSFER_SOURCE_FLAGS.TSF_COPY_LOCALIZED_NAME, - - /// Move as a copy and delete operation. - MoveAsCopyDelete = TRANSFER_SOURCE_FLAGS.TSF_MOVE_AS_COPY_DELETE, - - /// Suspend Shell events. - SuspendShellEvents = TRANSFER_SOURCE_FLAGS.TSF_SUSPEND_SHELLEVENTS, - } - /// /// Gets a value that states whether any file operations initiated by a call to were stopped before /// they were complete. The operations could be stopped either by user action or silently by the system. @@ -781,71 +584,6 @@ namespace Vanara.Windows.Shell private IShellItemArray GetSHArray(IEnumerable items) => items is ShellItemArray a ? a.IShellItemArray : GetSHArray(items); - /// Arguments supplied to the event. - /// - public class ShellFileNewOpEventArgs : ShellFileOpEventArgs - { - internal ShellFileNewOpEventArgs(TRANSFER_SOURCE_FLAGS flags, IShellItem source, IShellItem folder, IShellItem dest, string name, HRESULT hr, string templ, uint attr) : - base(flags, source, folder, dest, name, hr) - { - TemplateName = templ; - FileAttributes = (System.IO.FileAttributes)attr; - } - - /// Gets the name of the template. - /// The name of the template. - public string TemplateName { get; protected set; } - - /// Gets the file attributes. - /// The file attributes. - public System.IO.FileAttributes FileAttributes { get; protected set; } - } - - /// - /// Arguments supplied to events from . Depending on the event, some properties may not be set. - /// - /// - public class ShellFileOpEventArgs : EventArgs - { - internal ShellFileOpEventArgs(TRANSFER_SOURCE_FLAGS flags, IShellItem source, IShellItem folder = null, IShellItem dest = null, string name = null, HRESULT hr = default) - { - Flags = (TransferFlags)flags; - if (source != null) SourceItem = ShellItem.Open(source); - if (folder != null) DestFolder = ShellItem.Open(folder); - if (dest != null) DestItem = ShellItem.Open(dest); - Name = name; - Result = hr; - } - - /// Gets the destination folder. - /// The destination folder. - public ShellItem DestFolder { get; protected set; } - - /// Gets the destination item. - /// The destination item. - public ShellItem DestItem { get; protected set; } - - /// Gets the tranfer flag values. - /// The flags. - public TransferFlags Flags { get; protected set; } - - /// Gets the name of the item. - /// The item name. - public string Name { get; protected set; } - - /// Gets the result of the operation. - /// The result. - public HRESULT Result { get; protected set; } - - /// Gets the source item. - /// The source item. - public ShellItem SourceItem { get; protected set; } - - /// Returns a that represents this instance. - /// A that represents this instance. - public override string ToString() => $"HR:{Result};Src:{SourceItem};DFld:{DestFolder};Dst:{DestItem};Name:{Name}"; - } - private class OpSink : IFileOperationProgressSink { private readonly ShellFileOperations parent; @@ -903,184 +641,4 @@ namespace Vanara.Windows.Shell public void UpdateProgress(uint iWorkTotal, uint iWorkSoFar) => parent.UpdateProgress?.Invoke(parent, new System.ComponentModel.ProgressChangedEventArgs(iWorkTotal == 0 ? 0 : (int)(iWorkSoFar * 100 / iWorkTotal), null)); } } - - /// - /// A dictionary of properties that can be used to set or update property values on Shell items via the method. This class wraps the COM interface. - /// - /// - /// - public class ShellItemPropertyUpdates : IDictionary, IDisposable - { - private IPropertyChangeArray changes; - - /// Initializes a new instance of the class. - public ShellItemPropertyUpdates() - { - PSCreatePropertyChangeArray(null, null, null, 0, typeof(IPropertyChangeArray).GUID, out changes).ThrowIfFailed(); - } - - /// Gets the number of elements contained in the . - public int Count => (int)changes.GetCount(); - - /// Gets the COM interface for . - /// The value. - public IPropertyChangeArray IPropertyChangeArray => changes; - - /// Gets an containing the keys of the . - public ICollection Keys - { - get - { - var l = new List(Count); - for (uint i = 0; i < Count; i++) - { - using var p = new ComReleaser(changes.GetAt(i)); - l.Add(p.Item.GetPropertyKey()); - } - return l; - } - } - - /// Gets an containing the values in the . - public ICollection Values - { - get - { - var l = new List(Count); - for (int i = 0; i < Count; i++) - l.Add(this[i].Value); - return l; - } - } - - /// Gets a value indicating whether the is read-only. - bool ICollection>.IsReadOnly => false; - - /// Gets or sets the with the specified key. - /// The . - /// The key. - /// The object associated with . - /// key - public object this[PROPERTYKEY key] - { - get => TryGetValue(key, out var value) ? value : throw new ArgumentOutOfRangeException(nameof(key)); - set => changes.AppendOrReplace(ToPC(key, value)); - } - - internal KeyValuePair this[int index] - { - get - { - using var p = new ComReleaser(changes.GetAt((uint)index)); - p.Item.ApplyToPropVariant(new PROPVARIANT(), out var pv); - return new KeyValuePair(p.Item.GetPropertyKey(), pv.Value); - } - } - - /// Adds an element with the provided key and value to the . - /// The object to use as the key of the element to add. - /// The object to use as the value of the element to add. - public void Add(PROPERTYKEY key, object value) - { - changes.Append(ToPC(key, value)); - } - - /// Removes all items from the . - public void Clear() - { - for (uint i = (uint)Count - 1; i >= 0; i--) - changes.RemoveAt(i); - } - - /// Determines whether the contains an element with the specified key. - /// The key to locate in the . - /// true if the contains an element with the key; otherwise, false. - public bool ContainsKey(PROPERTYKEY key) => changes.IsKeyInArray(key).Succeeded; - - /// Returns an enumerator that iterates through the collection. - /// A that can be used to iterate through the collection. - public IEnumerator> GetEnumerator() => - new IEnumFromIndexer>(changes.GetCount, i => this[(int)i]).GetEnumerator(); - - /// Removes the element with the specified key from the . - /// The key of the element to remove. - /// - /// true if the element is successfully removed; otherwise, false. This method also returns false if was not - /// found in the original . - /// - public bool Remove(PROPERTYKEY key) - { - var idx = IndexOf(key); - if (idx == -1) return false; - try { changes.RemoveAt((uint)idx); return true; } catch { return false; } - } - - /// Gets the value associated with the specified key. - /// The key whose value to get. - /// - /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the - /// type of the parameter. This parameter is passed uninitialized. - /// - /// - /// true if the object that implements contains an element with the specified key; - /// otherwise, false. - /// - public bool TryGetValue(PROPERTYKEY key, out object value) - { - value = null; - var idx = IndexOf(key); - if (idx == -1) return false; - try { value = this[idx]; return true; } catch { return false; } - } - - void ICollection>.Add(KeyValuePair item) => - Add(item.Key, item.Value); - - bool ICollection>.Contains(KeyValuePair item) => - ContainsKey(item.Key) && this[item.Key] == item.Value; - - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - if (array == null) throw new ArgumentNullException(nameof(array)); - if (arrayIndex + Count > array.Length) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); - for (int i = 0; i < Count; i++) - array[i + arrayIndex] = this[i]; - } - - void IDisposable.Dispose() - { - if (changes == null) return; - Marshal.FinalReleaseComObject(changes); - changes = null; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - bool ICollection>.Remove(KeyValuePair item) - { - var idx = IndexOf(item.Key); - if (idx == -1) return false; - if (this[idx].Value != item.Value) return false; - try { changes.RemoveAt((uint)idx); return true; } catch { return false; } - } - - private int IndexOf(PROPERTYKEY key) - { - for (uint i = 0; i < Count; i++) - { - using var p = new ComReleaser(changes.GetAt(i)); - if (key == p.Item.GetPropertyKey()) - return (int)i; - } - return -1; - } - - private IPropertyChange ToPC(PROPERTYKEY key, object value, PKA_FLAGS flags = PKA_FLAGS.PKA_SET) - { - PSCreateSimplePropertyChange(flags, key, new PROPVARIANT(value), typeof(IPropertyChange).GUID, out var pc).ThrowIfFailed(); - return pc; - } - } } \ No newline at end of file diff --git a/Windows.Shell/ShellFileOperations/ShellItemPropertyUpdates.cs b/Windows.Shell/ShellFileOperations/ShellItemPropertyUpdates.cs new file mode 100644 index 00000000..b2d605dc --- /dev/null +++ b/Windows.Shell/ShellFileOperations/ShellItemPropertyUpdates.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Vanara.Collections; +using Vanara.InteropServices; +using static Vanara.PInvoke.Ole32; +using static Vanara.PInvoke.PropSys; + +namespace Vanara.Windows.Shell +{ + /// + /// A dictionary of properties that can be used to set or update property values on Shell items via the method. This class wraps the COM interface. + /// + /// + /// + public class ShellItemPropertyUpdates : IDictionary, IDisposable + { + private IPropertyChangeArray changes; + + /// Initializes a new instance of the class. + public ShellItemPropertyUpdates() + { + PSCreatePropertyChangeArray(null, null, null, 0, typeof(IPropertyChangeArray).GUID, out changes).ThrowIfFailed(); + } + + /// Gets the number of elements contained in the . + public int Count => (int)changes.GetCount(); + + /// Gets the COM interface for . + /// The value. + public IPropertyChangeArray IPropertyChangeArray => changes; + + /// Gets an containing the keys of the . + public ICollection Keys + { + get + { + var l = new List(Count); + for (uint i = 0; i < Count; i++) + { + using var p = new ComReleaser(changes.GetAt(i)); + l.Add(p.Item.GetPropertyKey()); + } + return l; + } + } + + /// Gets an containing the values in the . + public ICollection Values + { + get + { + var l = new List(Count); + for (int i = 0; i < Count; i++) + l.Add(this[i].Value); + return l; + } + } + + /// Gets a value indicating whether the is read-only. + bool ICollection>.IsReadOnly => false; + + /// Gets or sets the with the specified key. + /// The . + /// The key. + /// The object associated with . + /// key + public object this[PROPERTYKEY key] + { + get => TryGetValue(key, out var value) ? value : throw new ArgumentOutOfRangeException(nameof(key)); + set => changes.AppendOrReplace(ToPC(key, value)); + } + + internal KeyValuePair this[int index] + { + get + { + using var p = new ComReleaser(changes.GetAt((uint)index)); + p.Item.ApplyToPropVariant(new PROPVARIANT(), out var pv); + return new KeyValuePair(p.Item.GetPropertyKey(), pv.Value); + } + } + + /// Adds an element with the provided key and value to the . + /// The object to use as the key of the element to add. + /// The object to use as the value of the element to add. + public void Add(PROPERTYKEY key, object value) + { + changes.Append(ToPC(key, value)); + } + + /// Removes all items from the . + public void Clear() + { + for (uint i = (uint)Count - 1; i >= 0; i--) + changes.RemoveAt(i); + } + + /// Determines whether the contains an element with the specified key. + /// The key to locate in the . + /// true if the contains an element with the key; otherwise, false. + public bool ContainsKey(PROPERTYKEY key) => changes.IsKeyInArray(key).Succeeded; + + /// Returns an enumerator that iterates through the collection. + /// A that can be used to iterate through the collection. + public IEnumerator> GetEnumerator() => + new IEnumFromIndexer>(changes.GetCount, i => this[(int)i]).GetEnumerator(); + + /// Removes the element with the specified key from the . + /// The key of the element to remove. + /// + /// true if the element is successfully removed; otherwise, false. This method also returns false if was not + /// found in the original . + /// + public bool Remove(PROPERTYKEY key) + { + var idx = IndexOf(key); + if (idx == -1) return false; + try { changes.RemoveAt((uint)idx); return true; } catch { return false; } + } + + /// Gets the value associated with the specified key. + /// The key whose value to get. + /// + /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the + /// type of the parameter. This parameter is passed uninitialized. + /// + /// + /// true if the object that implements contains an element with the specified key; + /// otherwise, false. + /// + public bool TryGetValue(PROPERTYKEY key, out object value) + { + value = null; + var idx = IndexOf(key); + if (idx == -1) return false; + try { value = this[idx]; return true; } catch { return false; } + } + + void ICollection>.Add(KeyValuePair item) => + Add(item.Key, item.Value); + + bool ICollection>.Contains(KeyValuePair item) => + ContainsKey(item.Key) && this[item.Key] == item.Value; + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + if (array == null) throw new ArgumentNullException(nameof(array)); + if (arrayIndex + Count > array.Length) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + for (int i = 0; i < Count; i++) + array[i + arrayIndex] = this[i]; + } + + void IDisposable.Dispose() + { + if (changes == null) return; + Marshal.FinalReleaseComObject(changes); + changes = null; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + bool ICollection>.Remove(KeyValuePair item) + { + var idx = IndexOf(item.Key); + if (idx == -1) return false; + if (this[idx].Value != item.Value) return false; + try { changes.RemoveAt((uint)idx); return true; } catch { return false; } + } + + private int IndexOf(PROPERTYKEY key) + { + for (uint i = 0; i < Count; i++) + { + using var p = new ComReleaser(changes.GetAt(i)); + if (key == p.Item.GetPropertyKey()) + return (int)i; + } + return -1; + } + + private IPropertyChange ToPC(PROPERTYKEY key, object value, PKA_FLAGS flags = PKA_FLAGS.PKA_SET) + { + PSCreateSimplePropertyChange(flags, key, new PROPVARIANT(value), typeof(IPropertyChange).GUID, out var pc).ThrowIfFailed(); + return pc; + } + } +} \ No newline at end of file