mirror of https://github.com/dahall/Vanara.git
Pulled classes and enums out of ShellFileOperations.cs into thier own files.
parent
e2808812b7
commit
b8c0ce3f0f
|
@ -0,0 +1,205 @@
|
|||
using System;
|
||||
using static Vanara.PInvoke.Shell32;
|
||||
|
||||
namespace Vanara.Windows.Shell
|
||||
{
|
||||
public partial class ShellFileOperations
|
||||
{
|
||||
/// <summary>Flags that control the file operation.</summary>
|
||||
[Flags]
|
||||
public enum OperationFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
MultiDestFiles = FILEOP_FLAGS.FOF_MULTIDESTFILES,
|
||||
|
||||
/// <summary>Do not display a progress dialog box.</summary>
|
||||
Silent = FILEOP_FLAGS.FOF_SILENT,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
RenameOnCollision = FILEOP_FLAGS.FOF_RENAMEONCOLLISION,
|
||||
|
||||
/// <summary>Respond with Yes to All for any dialog box that is displayed.</summary>
|
||||
NoConfirmation = FILEOP_FLAGS.FOF_NOCONFIRMATION,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
WantMappingHandle = FILEOP_FLAGS.FOF_WANTMAPPINGHANDLE,
|
||||
|
||||
/// <summary>
|
||||
/// Preserve undo information, if possible.
|
||||
/// <para>Prior to Windows Vista, operations could be undone only from the same process that performed the original operation.</para>
|
||||
/// <para>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// <para>If the source file parameter does not contain fully qualified path and file names, this flag is ignored.</para>
|
||||
/// </summary>
|
||||
AllowUndo = FILEOP_FLAGS.FOF_ALLOWUNDO,
|
||||
|
||||
/// <summary>Perform the operation only on files (not on folders) if a wildcard file name (*.*) is specified.</summary>
|
||||
FilesOnly = FILEOP_FLAGS.FOF_FILESONLY,
|
||||
|
||||
/// <summary>Display a progress dialog box but do not show individual file names as they are operated on.</summary>
|
||||
SimpleProgress = FILEOP_FLAGS.FOF_SIMPLEPROGRESS,
|
||||
|
||||
/// <summary>Do not confirm the creation of a new folder if the operation requires one to be created.</summary>
|
||||
NoConfirmMkDir = FILEOP_FLAGS.FOF_NOCONFIRMMKDIR,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
NoErrorUI = FILEOP_FLAGS.FOF_NOERRORUI,
|
||||
|
||||
/// <summary>Do not copy the security attributes of the item.</summary>
|
||||
NoCopySecurityAttribs = FILEOP_FLAGS.FOF_NOCOPYSECURITYATTRIBS,
|
||||
|
||||
/// <summary>Only operate in the local folder. Do not operate recursively into subdirectories.</summary>
|
||||
NoRecursion = FILEOP_FLAGS.FOF_NORECURSION,
|
||||
|
||||
/// <summary>Do not move connected items as a group. Only move the specified files.</summary>
|
||||
NoConnectedElements = FILEOP_FLAGS.FOF_NO_CONNECTED_ELEMENTS,
|
||||
|
||||
/// <summary>
|
||||
/// Send a warning if a file or folder is being destroyed during a delete operation rather than recycled. This flag partially
|
||||
/// overrides FOF_NOCONFIRMATION.
|
||||
/// </summary>
|
||||
WantNukeWarning = FILEOP_FLAGS.FOF_WANTNUKEWARNING,
|
||||
|
||||
/// <summary>Don't display any UI at all.</summary>
|
||||
NoUI = FILEOP_FLAGS.FOF_NO_UI,
|
||||
|
||||
/// <summary>
|
||||
/// Walk into Shell namespace junctions. By default, junctions are not entered. For more information on junctions, see
|
||||
/// Specifying a Namespace Extension's Location.
|
||||
/// </summary>
|
||||
NoSkipJunctions = FILEOP_FLAGS.FOFX_NOSKIPJUNCTIONS,
|
||||
|
||||
/// <summary>If possible, create a hard link rather than a new instance of the file in the destination.</summary>
|
||||
PreferHardLink = FILEOP_FLAGS.FOFX_PREFERHARDLINK,
|
||||
|
||||
/// <summary>
|
||||
/// If an operation requires elevated rights and the FOF_NOERRORUI flag is set to disable error UI, display a UAC UI prompt nonetheless.
|
||||
/// </summary>
|
||||
ShowElevationPrompt = FILEOP_FLAGS.FOFX_SHOWELEVATIONPROMPT,
|
||||
|
||||
/// <summary>
|
||||
/// Introduced in Windows 8. When a file is deleted, send it to the Recycle Bin rather than permanently deleting it.
|
||||
/// </summary>
|
||||
RecycleOnDelete = FILEOP_FLAGS.FOFX_RECYCLEONDELETE,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
EarlyFailure = FILEOP_FLAGS.FOFX_EARLYFAILURE,
|
||||
|
||||
/// <summary>
|
||||
/// Rename collisions in such a way as to preserve file name extensions. This flag is valid only when FOF_RENAMEONCOLLISION is
|
||||
/// also set.
|
||||
/// </summary>
|
||||
PreserveFileExtensions = FILEOP_FLAGS.FOFX_PRESERVEFILEEXTENSIONS,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
KeepNewerFile = FILEOP_FLAGS.FOFX_KEEPNEWERFILE,
|
||||
|
||||
/// <summary>Do not use copy hooks.</summary>
|
||||
NoCopyHooks = FILEOP_FLAGS.FOFX_NOCOPYHOOKS,
|
||||
|
||||
/// <summary>Do not allow the progress dialog to be minimized.</summary>
|
||||
NoMinimizeBox = FILEOP_FLAGS.FOFX_NOMINIMIZEBOX,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
MoveACLsAcrossVolumes = FILEOP_FLAGS.FOFX_MOVEACLSACROSSVOLUMES,
|
||||
|
||||
/// <summary>Do not display the path of the source item in the progress dialog.</summary>
|
||||
DontDisplaySourcePath = FILEOP_FLAGS.FOFX_DONTDISPLAYSOURCEPATH,
|
||||
|
||||
/// <summary>Do not display the path of the destination item in the progress dialog.</summary>
|
||||
DontDisplayDestPath = FILEOP_FLAGS.FOFX_DONTDISPLAYDESTPATH,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
RequireElevation = FILEOP_FLAGS.FOFX_REQUIREELEVATION,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
AddUndoRecord = FILEOP_FLAGS.FOFX_ADDUNDORECORD,
|
||||
|
||||
/// <summary>Introduced in Windows 7. Display a Downloading instead of Copying message in the progress dialog.</summary>
|
||||
CopyAsDownload = FILEOP_FLAGS.FOFX_COPYASDOWNLOAD,
|
||||
|
||||
/// <summary>Introduced in Windows 7. Do not display the location line in the progress dialog.</summary>
|
||||
DontDisplayLocations = FILEOP_FLAGS.FOFX_DONTDISPLAYLOCATIONS,
|
||||
}
|
||||
|
||||
/// <summary>Used by methods of the ITransferSource and ITransferDestination interfaces to control their file operations.</summary>
|
||||
[Flags]
|
||||
public enum TransferFlags
|
||||
{
|
||||
/// <summary>Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior.</summary>
|
||||
Normal = TRANSFER_SOURCE_FLAGS.TSF_NORMAL,
|
||||
|
||||
/// <summary>Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior</summary>
|
||||
FailExist = TRANSFER_SOURCE_FLAGS.TSF_FAIL_EXIST,
|
||||
|
||||
/// <summary>Rename with auto-name generation if the destination already exists.</summary>
|
||||
RenameExist = TRANSFER_SOURCE_FLAGS.TSF_RENAME_EXIST,
|
||||
|
||||
/// <summary>Overwrite or merge with the destination.</summary>
|
||||
OverwriteExist = TRANSFER_SOURCE_FLAGS.TSF_OVERWRITE_EXIST,
|
||||
|
||||
/// <summary>Allow creation of a decrypted destination.</summary>
|
||||
AllowDecryption = TRANSFER_SOURCE_FLAGS.TSF_ALLOW_DECRYPTION,
|
||||
|
||||
/// <summary>No discretionary access control list (DACL), system access control list (SACL), or owner.</summary>
|
||||
NoSecurity = TRANSFER_SOURCE_FLAGS.TSF_NO_SECURITY,
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
CopyCreationTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_CREATION_TIME,
|
||||
|
||||
/// <summary>Copy the last write time as part of the copy.</summary>
|
||||
CopyWriteTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_WRITE_TIME,
|
||||
|
||||
/// <summary>Assign write, read, and delete permissions as share mode.</summary>
|
||||
UseFullAccess = TRANSFER_SOURCE_FLAGS.TSF_USE_FULL_ACCESS,
|
||||
|
||||
/// <summary>Recycle on file delete, if possible.</summary>
|
||||
DeleteRecycleIfPossible = TRANSFER_SOURCE_FLAGS.TSF_DELETE_RECYCLE_IF_POSSIBLE,
|
||||
|
||||
/// <summary>Hard link to the desired source (not required). This avoids a normal copy operation.</summary>
|
||||
CopyHardLink = TRANSFER_SOURCE_FLAGS.TSF_COPY_HARD_LINK,
|
||||
|
||||
/// <summary>Copy the localized name.</summary>
|
||||
CopyLocalizedName = TRANSFER_SOURCE_FLAGS.TSF_COPY_LOCALIZED_NAME,
|
||||
|
||||
/// <summary>Move as a copy and delete operation.</summary>
|
||||
MoveAsCopyDelete = TRANSFER_SOURCE_FLAGS.TSF_MOVE_AS_COPY_DELETE,
|
||||
|
||||
/// <summary>Suspend Shell events.</summary>
|
||||
SuspendShellEvents = TRANSFER_SOURCE_FLAGS.TSF_SUSPEND_SHELLEVENTS,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using Vanara.PInvoke;
|
||||
using static Vanara.PInvoke.Shell32;
|
||||
|
||||
namespace Vanara.Windows.Shell
|
||||
{
|
||||
public partial class ShellFileOperations
|
||||
{
|
||||
/// <summary>Arguments supplied to the <see cref="PostNewItem"/> event.</summary>
|
||||
/// <seealso cref="ShellFileOpEventArgs"/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>Gets the name of the template.</summary>
|
||||
/// <value>The name of the template.</value>
|
||||
public string TemplateName { get; protected set; }
|
||||
|
||||
/// <summary>Gets the file attributes.</summary>
|
||||
/// <value>The file attributes.</value>
|
||||
public System.IO.FileAttributes FileAttributes { get; protected set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments supplied to events from <see cref="ShellFileOperations"/>. Depending on the event, some properties may not be set.
|
||||
/// </summary>
|
||||
/// <seealso cref="EventArgs"/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>Gets the destination folder.</summary>
|
||||
/// <value>The destination folder.</value>
|
||||
public ShellItem DestFolder { get; protected set; }
|
||||
|
||||
/// <summary>Gets the destination item.</summary>
|
||||
/// <value>The destination item.</value>
|
||||
public ShellItem DestItem { get; protected set; }
|
||||
|
||||
/// <summary>Gets the tranfer flag values.</summary>
|
||||
/// <value>The flags.</value>
|
||||
public TransferFlags Flags { get; protected set; }
|
||||
|
||||
/// <summary>Gets the name of the item.</summary>
|
||||
/// <value>The item name.</value>
|
||||
public string Name { get; protected set; }
|
||||
|
||||
/// <summary>Gets the result of the operation.</summary>
|
||||
/// <value>The result.</value>
|
||||
public HRESULT Result { get; protected set; }
|
||||
|
||||
/// <summary>Gets the source item.</summary>
|
||||
/// <value>The source item.</value>
|
||||
public ShellItem SourceItem { get; protected set; }
|
||||
|
||||
/// <summary>Returns a <see cref="System.String"/> that represents this instance.</summary>
|
||||
/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
|
||||
public override string ToString() => $"HR:{Result};Src:{SourceItem};DFld:{DestFolder};Dst:{DestItem};Name:{Name}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ namespace Vanara.Windows.Shell
|
|||
{
|
||||
/// <summary>Queued and static file operations using the Shell.</summary>
|
||||
/// <seealso cref="IDisposable"/>
|
||||
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
|
|||
/// <summary>Occurs when a progress update is received.</summary>
|
||||
public event System.ComponentModel.ProgressChangedEventHandler UpdateProgress;
|
||||
|
||||
/// <summary>Flags that control the file operation.</summary>
|
||||
[Flags]
|
||||
public enum OperationFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
MultiDestFiles = FILEOP_FLAGS.FOF_MULTIDESTFILES,
|
||||
|
||||
/// <summary>Do not display a progress dialog box.</summary>
|
||||
Silent = FILEOP_FLAGS.FOF_SILENT,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
RenameOnCollision = FILEOP_FLAGS.FOF_RENAMEONCOLLISION,
|
||||
|
||||
/// <summary>Respond with Yes to All for any dialog box that is displayed.</summary>
|
||||
NoConfirmation = FILEOP_FLAGS.FOF_NOCONFIRMATION,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
WantMappingHandle = FILEOP_FLAGS.FOF_WANTMAPPINGHANDLE,
|
||||
|
||||
/// <summary>
|
||||
/// Preserve undo information, if possible.
|
||||
/// <para>Prior to Windows Vista, operations could be undone only from the same process that performed the original operation.</para>
|
||||
/// <para>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// <para>If the source file parameter does not contain fully qualified path and file names, this flag is ignored.</para>
|
||||
/// </summary>
|
||||
AllowUndo = FILEOP_FLAGS.FOF_ALLOWUNDO,
|
||||
|
||||
/// <summary>Perform the operation only on files (not on folders) if a wildcard file name (*.*) is specified.</summary>
|
||||
FilesOnly = FILEOP_FLAGS.FOF_FILESONLY,
|
||||
|
||||
/// <summary>Display a progress dialog box but do not show individual file names as they are operated on.</summary>
|
||||
SimpleProgress = FILEOP_FLAGS.FOF_SIMPLEPROGRESS,
|
||||
|
||||
/// <summary>Do not confirm the creation of a new folder if the operation requires one to be created.</summary>
|
||||
NoConfirmMkDir = FILEOP_FLAGS.FOF_NOCONFIRMMKDIR,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
NoErrorUI = FILEOP_FLAGS.FOF_NOERRORUI,
|
||||
|
||||
/// <summary>Do not copy the security attributes of the item.</summary>
|
||||
NoCopySecurityAttribs = FILEOP_FLAGS.FOF_NOCOPYSECURITYATTRIBS,
|
||||
|
||||
/// <summary>Only operate in the local folder. Do not operate recursively into subdirectories.</summary>
|
||||
NoRecursion = FILEOP_FLAGS.FOF_NORECURSION,
|
||||
|
||||
/// <summary>Do not move connected items as a group. Only move the specified files.</summary>
|
||||
NoConnectedElements = FILEOP_FLAGS.FOF_NO_CONNECTED_ELEMENTS,
|
||||
|
||||
/// <summary>
|
||||
/// Send a warning if a file or folder is being destroyed during a delete operation rather than recycled. This flag partially
|
||||
/// overrides FOF_NOCONFIRMATION.
|
||||
/// </summary>
|
||||
WantNukeWarning = FILEOP_FLAGS.FOF_WANTNUKEWARNING,
|
||||
|
||||
/// <summary>Don't display any UI at all.</summary>
|
||||
NoUI = FILEOP_FLAGS.FOF_NO_UI,
|
||||
|
||||
/// <summary>
|
||||
/// Walk into Shell namespace junctions. By default, junctions are not entered. For more information on junctions, see
|
||||
/// Specifying a Namespace Extension's Location.
|
||||
/// </summary>
|
||||
NoSkipJunctions = FILEOP_FLAGS.FOFX_NOSKIPJUNCTIONS,
|
||||
|
||||
/// <summary>If possible, create a hard link rather than a new instance of the file in the destination.</summary>
|
||||
PreferHardLink = FILEOP_FLAGS.FOFX_PREFERHARDLINK,
|
||||
|
||||
/// <summary>
|
||||
/// If an operation requires elevated rights and the FOF_NOERRORUI flag is set to disable error UI, display a UAC UI prompt nonetheless.
|
||||
/// </summary>
|
||||
ShowElevationPrompt = FILEOP_FLAGS.FOFX_SHOWELEVATIONPROMPT,
|
||||
|
||||
/// <summary>
|
||||
/// Introduced in Windows 8. When a file is deleted, send it to the Recycle Bin rather than permanently deleting it.
|
||||
/// </summary>
|
||||
RecycleOnDelete = FILEOP_FLAGS.FOFX_RECYCLEONDELETE,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
EarlyFailure = FILEOP_FLAGS.FOFX_EARLYFAILURE,
|
||||
|
||||
/// <summary>
|
||||
/// Rename collisions in such a way as to preserve file name extensions. This flag is valid only when FOF_RENAMEONCOLLISION is
|
||||
/// also set.
|
||||
/// </summary>
|
||||
PreserveFileExtensions = FILEOP_FLAGS.FOFX_PRESERVEFILEEXTENSIONS,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
KeepNewerFile = FILEOP_FLAGS.FOFX_KEEPNEWERFILE,
|
||||
|
||||
/// <summary>Do not use copy hooks.</summary>
|
||||
NoCopyHooks = FILEOP_FLAGS.FOFX_NOCOPYHOOKS,
|
||||
|
||||
/// <summary>Do not allow the progress dialog to be minimized.</summary>
|
||||
NoMinimizeBox = FILEOP_FLAGS.FOFX_NOMINIMIZEBOX,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
MoveACLsAcrossVolumes = FILEOP_FLAGS.FOFX_MOVEACLSACROSSVOLUMES,
|
||||
|
||||
/// <summary>Do not display the path of the source item in the progress dialog.</summary>
|
||||
DontDisplaySourcePath = FILEOP_FLAGS.FOFX_DONTDISPLAYSOURCEPATH,
|
||||
|
||||
/// <summary>Do not display the path of the destination item in the progress dialog.</summary>
|
||||
DontDisplayDestPath = FILEOP_FLAGS.FOFX_DONTDISPLAYDESTPATH,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
RequireElevation = FILEOP_FLAGS.FOFX_REQUIREELEVATION,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
AddUndoRecord = FILEOP_FLAGS.FOFX_ADDUNDORECORD,
|
||||
|
||||
/// <summary>Introduced in Windows 7. Display a Downloading instead of Copying message in the progress dialog.</summary>
|
||||
CopyAsDownload = FILEOP_FLAGS.FOFX_COPYASDOWNLOAD,
|
||||
|
||||
/// <summary>Introduced in Windows 7. Do not display the location line in the progress dialog.</summary>
|
||||
DontDisplayLocations = FILEOP_FLAGS.FOFX_DONTDISPLAYLOCATIONS,
|
||||
}
|
||||
|
||||
/// <summary>Used by methods of the ITransferSource and ITransferDestination interfaces to control their file operations.</summary>
|
||||
[Flags]
|
||||
public enum TransferFlags
|
||||
{
|
||||
/// <summary>Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior.</summary>
|
||||
Normal = TRANSFER_SOURCE_FLAGS.TSF_NORMAL,
|
||||
|
||||
/// <summary>Fail if the destination already exists, unless TSF_OVERWRITE_EXIST is specified. This is a default behavior</summary>
|
||||
FailExist = TRANSFER_SOURCE_FLAGS.TSF_FAIL_EXIST,
|
||||
|
||||
/// <summary>Rename with auto-name generation if the destination already exists.</summary>
|
||||
RenameExist = TRANSFER_SOURCE_FLAGS.TSF_RENAME_EXIST,
|
||||
|
||||
/// <summary>Overwrite or merge with the destination.</summary>
|
||||
OverwriteExist = TRANSFER_SOURCE_FLAGS.TSF_OVERWRITE_EXIST,
|
||||
|
||||
/// <summary>Allow creation of a decrypted destination.</summary>
|
||||
AllowDecryption = TRANSFER_SOURCE_FLAGS.TSF_ALLOW_DECRYPTION,
|
||||
|
||||
/// <summary>No discretionary access control list (DACL), system access control list (SACL), or owner.</summary>
|
||||
NoSecurity = TRANSFER_SOURCE_FLAGS.TSF_NO_SECURITY,
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
CopyCreationTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_CREATION_TIME,
|
||||
|
||||
/// <summary>Copy the last write time as part of the copy.</summary>
|
||||
CopyWriteTime = TRANSFER_SOURCE_FLAGS.TSF_COPY_WRITE_TIME,
|
||||
|
||||
/// <summary>Assign write, read, and delete permissions as share mode.</summary>
|
||||
UseFullAccess = TRANSFER_SOURCE_FLAGS.TSF_USE_FULL_ACCESS,
|
||||
|
||||
/// <summary>Recycle on file delete, if possible.</summary>
|
||||
DeleteRecycleIfPossible = TRANSFER_SOURCE_FLAGS.TSF_DELETE_RECYCLE_IF_POSSIBLE,
|
||||
|
||||
/// <summary>Hard link to the desired source (not required). This avoids a normal copy operation.</summary>
|
||||
CopyHardLink = TRANSFER_SOURCE_FLAGS.TSF_COPY_HARD_LINK,
|
||||
|
||||
/// <summary>Copy the localized name.</summary>
|
||||
CopyLocalizedName = TRANSFER_SOURCE_FLAGS.TSF_COPY_LOCALIZED_NAME,
|
||||
|
||||
/// <summary>Move as a copy and delete operation.</summary>
|
||||
MoveAsCopyDelete = TRANSFER_SOURCE_FLAGS.TSF_MOVE_AS_COPY_DELETE,
|
||||
|
||||
/// <summary>Suspend Shell events.</summary>
|
||||
SuspendShellEvents = TRANSFER_SOURCE_FLAGS.TSF_SUSPEND_SHELLEVENTS,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that states whether any file operations initiated by a call to <see cref="PerformOperations"/> 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<ShellItem> items) => items is ShellItemArray a ? a.IShellItemArray : GetSHArray(items);
|
||||
|
||||
/// <summary>Arguments supplied to the <see cref="PostNewItem"/> event.</summary>
|
||||
/// <seealso cref="ShellFileOpEventArgs"/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>Gets the name of the template.</summary>
|
||||
/// <value>The name of the template.</value>
|
||||
public string TemplateName { get; protected set; }
|
||||
|
||||
/// <summary>Gets the file attributes.</summary>
|
||||
/// <value>The file attributes.</value>
|
||||
public System.IO.FileAttributes FileAttributes { get; protected set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments supplied to events from <see cref="ShellFileOperations"/>. Depending on the event, some properties may not be set.
|
||||
/// </summary>
|
||||
/// <seealso cref="EventArgs"/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>Gets the destination folder.</summary>
|
||||
/// <value>The destination folder.</value>
|
||||
public ShellItem DestFolder { get; protected set; }
|
||||
|
||||
/// <summary>Gets the destination item.</summary>
|
||||
/// <value>The destination item.</value>
|
||||
public ShellItem DestItem { get; protected set; }
|
||||
|
||||
/// <summary>Gets the tranfer flag values.</summary>
|
||||
/// <value>The flags.</value>
|
||||
public TransferFlags Flags { get; protected set; }
|
||||
|
||||
/// <summary>Gets the name of the item.</summary>
|
||||
/// <value>The item name.</value>
|
||||
public string Name { get; protected set; }
|
||||
|
||||
/// <summary>Gets the result of the operation.</summary>
|
||||
/// <value>The result.</value>
|
||||
public HRESULT Result { get; protected set; }
|
||||
|
||||
/// <summary>Gets the source item.</summary>
|
||||
/// <value>The source item.</value>
|
||||
public ShellItem SourceItem { get; protected set; }
|
||||
|
||||
/// <summary>Returns a <see cref="System.String"/> that represents this instance.</summary>
|
||||
/// <returns>A <see cref="System.String"/> that represents this instance.</returns>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary of properties that can be used to set or update property values on Shell items via the <see
|
||||
/// cref="ShellFileOperations.QueueApplyPropertiesOperation(ShellItem, ShellItemPropertyUpdates)"/> method. This class wraps the <see
|
||||
/// cref="IPropertyChangeArray"/> COM interface.
|
||||
/// </summary>
|
||||
/// <seealso cref="IDictionary{TKey, TValue}"/>
|
||||
/// <seealso cref="IDisposable"/>
|
||||
public class ShellItemPropertyUpdates : IDictionary<PROPERTYKEY, object>, IDisposable
|
||||
{
|
||||
private IPropertyChangeArray changes;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ShellItemPropertyUpdates"/> class.</summary>
|
||||
public ShellItemPropertyUpdates()
|
||||
{
|
||||
PSCreatePropertyChangeArray(null, null, null, 0, typeof(IPropertyChangeArray).GUID, out changes).ThrowIfFailed();
|
||||
}
|
||||
|
||||
/// <summary>Gets the number of elements contained in the <see cref="ICollection{T}"/>.</summary>
|
||||
public int Count => (int)changes.GetCount();
|
||||
|
||||
/// <summary>Gets the COM interface for <see cref="IPropertyChangeArray"/>.</summary>
|
||||
/// <value>The <see cref="IPropertyChangeArray"/> value.</value>
|
||||
public IPropertyChangeArray IPropertyChangeArray => changes;
|
||||
|
||||
/// <summary>Gets an <see cref="ICollection{T}"/> containing the keys of the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
public ICollection<PROPERTYKEY> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
var l = new List<PROPERTYKEY>(Count);
|
||||
for (uint i = 0; i < Count; i++)
|
||||
{
|
||||
using var p = new ComReleaser<IPropertyChange>(changes.GetAt<IPropertyChange>(i));
|
||||
l.Add(p.Item.GetPropertyKey());
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets an <see cref="ICollection{T}"/> containing the values in the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
public ICollection<object> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
var l = new List<object>(Count);
|
||||
for (int i = 0; i < Count; i++)
|
||||
l.Add(this[i].Value);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets a value indicating whether the <see cref="ICollection{T}"/> is read-only.</summary>
|
||||
bool ICollection<KeyValuePair<PROPERTYKEY, object>>.IsReadOnly => false;
|
||||
|
||||
/// <summary>Gets or sets the <see cref="System.Object"/> with the specified key.</summary>
|
||||
/// <value>The <see cref="System.Object"/>.</value>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>The object associated with <paramref name="key"/>.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">key</exception>
|
||||
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<PROPERTYKEY, object> this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
using var p = new ComReleaser<IPropertyChange>(changes.GetAt<IPropertyChange>((uint)index));
|
||||
p.Item.ApplyToPropVariant(new PROPVARIANT(), out var pv);
|
||||
return new KeyValuePair<PROPERTYKEY, object>(p.Item.GetPropertyKey(), pv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Adds an element with the provided key and value to the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
/// <param name="key">The object to use as the key of the element to add.</param>
|
||||
/// <param name="value">The object to use as the value of the element to add.</param>
|
||||
public void Add(PROPERTYKEY key, object value)
|
||||
{
|
||||
changes.Append(ToPC(key, value));
|
||||
}
|
||||
|
||||
/// <summary>Removes all items from the <see cref="ICollection{T}"/>.</summary>
|
||||
public void Clear()
|
||||
{
|
||||
for (uint i = (uint)Count - 1; i >= 0; i--)
|
||||
changes.RemoveAt(i);
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the <see cref="IDictionary{TKey, TValue}"/> contains an element with the specified key.</summary>
|
||||
/// <param name="key">The key to locate in the <see cref="IDictionary{TKey, TValue}"/>.</param>
|
||||
/// <returns>true if the <see cref="IDictionary{TKey, TValue}"/> contains an element with the key; otherwise, false.</returns>
|
||||
public bool ContainsKey(PROPERTYKEY key) => changes.IsKeyInArray(key).Succeeded;
|
||||
|
||||
/// <summary>Returns an enumerator that iterates through the collection.</summary>
|
||||
/// <returns>A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.</returns>
|
||||
public IEnumerator<KeyValuePair<PROPERTYKEY, object>> GetEnumerator() =>
|
||||
new IEnumFromIndexer<KeyValuePair<PROPERTYKEY, object>>(changes.GetCount, i => this[(int)i]).GetEnumerator();
|
||||
|
||||
/// <summary>Removes the element with the specified key from the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
/// <param name="key">The key of the element to remove.</param>
|
||||
/// <returns>
|
||||
/// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not
|
||||
/// found in the original <see cref="IDictionary{TKey, TValue}"/>.
|
||||
/// </returns>
|
||||
public bool Remove(PROPERTYKEY key)
|
||||
{
|
||||
var idx = IndexOf(key);
|
||||
if (idx == -1) return false;
|
||||
try { changes.RemoveAt((uint)idx); return true; } catch { return false; }
|
||||
}
|
||||
|
||||
/// <summary>Gets the value associated with the specified key.</summary>
|
||||
/// <param name="key">The key whose value to get.</param>
|
||||
/// <param name="value">
|
||||
/// 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 <paramref name="value"/> parameter. This parameter is passed uninitialized.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the object that implements <see cref="IDictionary{TKey, TValue}"/> contains an element with the specified key;
|
||||
/// otherwise, false.
|
||||
/// </returns>
|
||||
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<KeyValuePair<PROPERTYKEY, object>>.Add(KeyValuePair<PROPERTYKEY, object> item) =>
|
||||
Add(item.Key, item.Value);
|
||||
|
||||
bool ICollection<KeyValuePair<PROPERTYKEY, object>>.Contains(KeyValuePair<PROPERTYKEY, object> item) =>
|
||||
ContainsKey(item.Key) && this[item.Key] == item.Value;
|
||||
|
||||
void ICollection<KeyValuePair<PROPERTYKEY, object>>.CopyTo(KeyValuePair<PROPERTYKEY, object>[] 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<KeyValuePair<PROPERTYKEY, object>>.Remove(KeyValuePair<PROPERTYKEY, object> 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<IPropertyChange>(changes.GetAt<IPropertyChange>(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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A dictionary of properties that can be used to set or update property values on Shell items via the <see
|
||||
/// cref="ShellFileOperations.QueueApplyPropertiesOperation(ShellItem, ShellItemPropertyUpdates)"/> method. This class wraps the <see
|
||||
/// cref="IPropertyChangeArray"/> COM interface.
|
||||
/// </summary>
|
||||
/// <seealso cref="IDictionary{TKey, TValue}"/>
|
||||
/// <seealso cref="IDisposable"/>
|
||||
public class ShellItemPropertyUpdates : IDictionary<PROPERTYKEY, object>, IDisposable
|
||||
{
|
||||
private IPropertyChangeArray changes;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ShellItemPropertyUpdates"/> class.</summary>
|
||||
public ShellItemPropertyUpdates()
|
||||
{
|
||||
PSCreatePropertyChangeArray(null, null, null, 0, typeof(IPropertyChangeArray).GUID, out changes).ThrowIfFailed();
|
||||
}
|
||||
|
||||
/// <summary>Gets the number of elements contained in the <see cref="ICollection{T}"/>.</summary>
|
||||
public int Count => (int)changes.GetCount();
|
||||
|
||||
/// <summary>Gets the COM interface for <see cref="IPropertyChangeArray"/>.</summary>
|
||||
/// <value>The <see cref="IPropertyChangeArray"/> value.</value>
|
||||
public IPropertyChangeArray IPropertyChangeArray => changes;
|
||||
|
||||
/// <summary>Gets an <see cref="ICollection{T}"/> containing the keys of the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
public ICollection<PROPERTYKEY> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
var l = new List<PROPERTYKEY>(Count);
|
||||
for (uint i = 0; i < Count; i++)
|
||||
{
|
||||
using var p = new ComReleaser<IPropertyChange>(changes.GetAt<IPropertyChange>(i));
|
||||
l.Add(p.Item.GetPropertyKey());
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets an <see cref="ICollection{T}"/> containing the values in the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
public ICollection<object> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
var l = new List<object>(Count);
|
||||
for (int i = 0; i < Count; i++)
|
||||
l.Add(this[i].Value);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets a value indicating whether the <see cref="ICollection{T}"/> is read-only.</summary>
|
||||
bool ICollection<KeyValuePair<PROPERTYKEY, object>>.IsReadOnly => false;
|
||||
|
||||
/// <summary>Gets or sets the <see cref="System.Object"/> with the specified key.</summary>
|
||||
/// <value>The <see cref="System.Object"/>.</value>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>The object associated with <paramref name="key"/>.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">key</exception>
|
||||
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<PROPERTYKEY, object> this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
using var p = new ComReleaser<IPropertyChange>(changes.GetAt<IPropertyChange>((uint)index));
|
||||
p.Item.ApplyToPropVariant(new PROPVARIANT(), out var pv);
|
||||
return new KeyValuePair<PROPERTYKEY, object>(p.Item.GetPropertyKey(), pv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Adds an element with the provided key and value to the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
/// <param name="key">The object to use as the key of the element to add.</param>
|
||||
/// <param name="value">The object to use as the value of the element to add.</param>
|
||||
public void Add(PROPERTYKEY key, object value)
|
||||
{
|
||||
changes.Append(ToPC(key, value));
|
||||
}
|
||||
|
||||
/// <summary>Removes all items from the <see cref="ICollection{T}"/>.</summary>
|
||||
public void Clear()
|
||||
{
|
||||
for (uint i = (uint)Count - 1; i >= 0; i--)
|
||||
changes.RemoveAt(i);
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the <see cref="IDictionary{TKey, TValue}"/> contains an element with the specified key.</summary>
|
||||
/// <param name="key">The key to locate in the <see cref="IDictionary{TKey, TValue}"/>.</param>
|
||||
/// <returns>true if the <see cref="IDictionary{TKey, TValue}"/> contains an element with the key; otherwise, false.</returns>
|
||||
public bool ContainsKey(PROPERTYKEY key) => changes.IsKeyInArray(key).Succeeded;
|
||||
|
||||
/// <summary>Returns an enumerator that iterates through the collection.</summary>
|
||||
/// <returns>A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.</returns>
|
||||
public IEnumerator<KeyValuePair<PROPERTYKEY, object>> GetEnumerator() =>
|
||||
new IEnumFromIndexer<KeyValuePair<PROPERTYKEY, object>>(changes.GetCount, i => this[(int)i]).GetEnumerator();
|
||||
|
||||
/// <summary>Removes the element with the specified key from the <see cref="IDictionary{TKey, TValue}"/>.</summary>
|
||||
/// <param name="key">The key of the element to remove.</param>
|
||||
/// <returns>
|
||||
/// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not
|
||||
/// found in the original <see cref="IDictionary{TKey, TValue}"/>.
|
||||
/// </returns>
|
||||
public bool Remove(PROPERTYKEY key)
|
||||
{
|
||||
var idx = IndexOf(key);
|
||||
if (idx == -1) return false;
|
||||
try { changes.RemoveAt((uint)idx); return true; } catch { return false; }
|
||||
}
|
||||
|
||||
/// <summary>Gets the value associated with the specified key.</summary>
|
||||
/// <param name="key">The key whose value to get.</param>
|
||||
/// <param name="value">
|
||||
/// 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 <paramref name="value"/> parameter. This parameter is passed uninitialized.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the object that implements <see cref="IDictionary{TKey, TValue}"/> contains an element with the specified key;
|
||||
/// otherwise, false.
|
||||
/// </returns>
|
||||
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<KeyValuePair<PROPERTYKEY, object>>.Add(KeyValuePair<PROPERTYKEY, object> item) =>
|
||||
Add(item.Key, item.Value);
|
||||
|
||||
bool ICollection<KeyValuePair<PROPERTYKEY, object>>.Contains(KeyValuePair<PROPERTYKEY, object> item) =>
|
||||
ContainsKey(item.Key) && this[item.Key] == item.Value;
|
||||
|
||||
void ICollection<KeyValuePair<PROPERTYKEY, object>>.CopyTo(KeyValuePair<PROPERTYKEY, object>[] 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<KeyValuePair<PROPERTYKEY, object>>.Remove(KeyValuePair<PROPERTYKEY, object> 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<IPropertyChange>(changes.GetAt<IPropertyChange>(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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue