Vanara/Windows.Shell.Common/ShellFileOperations/ShellFileOperations.cs

657 lines
30 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Vanara.Collections;
using Vanara.InteropServices;
using Vanara.PInvoke;
using static Vanara.PInvoke.Ole32;
using static Vanara.PInvoke.PropSys;
using static Vanara.PInvoke.Shell32;
namespace Vanara.Windows.Shell
{
/// <summary>Queued and static file operations using the Shell.</summary>
/// <seealso cref="IDisposable"/>
public partial class ShellFileOperations : IDisposable
{
private const OperationFlags defaultOptions = OperationFlags.AllowUndo | OperationFlags.NoConfirmMkDir;
private ShellFileOperationDialog customProgressDialog;
private bool disposedValue = false;
private IFileOperation op;
private OperationFlags opFlags = defaultOptions;
private HWND owner;
private IFileOperationProgressSink sink;
private uint sinkCookie;
/// <summary>Initializes a new instance of the <see cref="ShellFileOperations"/> class.</summary>
/// <param name="owner">The window that owns the modal dialog. This value can be <see langword="null"/>.</param>
public ShellFileOperations(HWND owner = default)
{
op = new IFileOperation();
if (owner != default) op.SetOwnerWindow(owner);
sink = new OpSink(this);
sinkCookie = op.Advise(sink);
}
/// <summary>Finalizes an instance of the <see cref="ShellFileOperations"/> class.</summary>
~ShellFileOperations()
{
Dispose(false);
}
/// <summary>Performs caller-implemented actions after the last operation performed by the call to IFileOperation is complete.</summary>
public event EventHandler<ShellFileOpEventArgs> FinishOperations;
/// <summary>Performs caller-implemented actions after the copy process for each item is complete.</summary>
public event EventHandler<ShellFileOpEventArgs> PostCopyItem;
/// <summary>Performs caller-implemented actions after the delete process for each item is complete.</summary>
public event EventHandler<ShellFileOpEventArgs> PostDeleteItem;
/// <summary>Performs caller-implemented actions after the move process for each item is complete.</summary>
public event EventHandler<ShellFileOpEventArgs> PostMoveItem;
/// <summary>Performs caller-implemented actions after the new item is created.</summary>
public event EventHandler<ShellFileNewOpEventArgs> PostNewItem;
/// <summary>Performs caller-implemented actions after the rename process for each item is complete.</summary>
public event EventHandler<ShellFileOpEventArgs> PostRenameItem;
/// <summary>Performs caller-implemented actions before the copy process for each item begins.</summary>
public event EventHandler<ShellFileOpEventArgs> PreCopyItem;
/// <summary>Performs caller-implemented actions before the delete process for each item begins.</summary>
public event EventHandler<ShellFileOpEventArgs> PreDeleteItem;
/// <summary>Performs caller-implemented actions before the move process for each item begins.</summary>
public event EventHandler<ShellFileOpEventArgs> PreMoveItem;
/// <summary>Performs caller-implemented actions before the process to create a new item begins.</summary>
public event EventHandler<ShellFileOpEventArgs> PreNewItem;
/// <summary>Performs caller-implemented actions before the rename process for each item begins.</summary>
public event EventHandler<ShellFileOpEventArgs> PreRenameItem;
/// <summary>Performs caller-implemented actions before any specific file operations are performed.</summary>
public event EventHandler StartOperations;
/// <summary>Occurs when a progress update is received.</summary>
public event System.ComponentModel.ProgressChangedEventHandler UpdateProgress;
/// <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.
/// </summary>
/// <value><see langword="true"/> if any file operations were aborted before they were complete; otherwise, <see langword="false"/>.</value>
public bool AnyOperationsAborted => op.GetAnyOperationsAborted();
/// <summary>Specifies a dialog box used to display the progress of the operation.</summary>
/// <value>A ShellFileOperationDialog object that represents the dialog box.</value>
public ShellFileOperationDialog CustomProgressDialog
{
get => customProgressDialog;
set => op.SetProgressDialog((customProgressDialog = value)?.iProgressDialog);
}
/// <summary>Gets or sets options that control file operations.</summary>
public OperationFlags Options
{
get => opFlags;
set { if (value == opFlags) return; op.SetOperationFlags((FILEOP_FLAGS)(opFlags = value)); }
}
/// <summary>Gets or sets the parent or owner window for progress and dialog windows.</summary>
/// <value>The owner window of the operation. This window will receive error messages.</value>
public HWND OwnerWindow
{
get => owner;
set => op.SetOwnerWindow(owner = value);
}
/// <summary>Gets the number of queued operations.</summary>
public int QueuedOperations { get; protected set; }
/// <summary>Copies a single item to a specified destination using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A string that specifies the source item's full file path.</param>
/// <param name="dest">A string that specifies the full path of the destination folder to contain the copy of the item.</param>
/// <param name="newName">
/// An optional new name for the item after it has been copied. This can be <see langword="null"/>. If <see langword="null"/>, the
/// name of the destination item is the same as the source.
/// </param>
/// <param name="options">Options that control file operations.</param>
public static void Copy(string source, string dest, string newName = null, OperationFlags options = defaultOptions)
{
using var shfile = new ShellItem(source);
using var shfld = new ShellFolder(dest);
Copy(shfile, shfld, newName, options);
}
/// <summary>Copies a single item to a specified destination using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the source item.</param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the copy of the item.</param>
/// <param name="newName">
/// An optional new name for the item after it has been copied. This can be <see langword="null"/>. If <see langword="null"/>, the
/// name of the destination item is the same as the source.
/// </param>
/// <param name="options">Options that control file operations.</param>
public static void Copy(ShellItem source, ShellFolder dest, string newName = null, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostCopyItem += OnPost;
try
{
sop.QueueCopyOperation(source, dest, newName);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostCopyItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Copies a set of items to a specified destination using the Shell to provide progress and error dialogs.</summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances that represent the group of items to be copied.
/// </param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the copy of the items.</param>
/// <param name="options">Options that control file operations.</param>
public static void Copy(IEnumerable<ShellItem> sourceItems, ShellFolder dest, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostCopyItem += OnPost;
try
{
sop.QueueCopyOperation(sourceItems, dest);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostCopyItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Deletes a single item using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A string that specifies the full path of the item to be deleted.</param>
/// <param name="options">Options that control file operations.</param>
public static void Delete(string source, OperationFlags options = defaultOptions)
{
using var shfile = new ShellItem(source);
Delete(shfile, options);
}
/// <summary>Deletes a single item using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the item to be deleted.</param>
/// <param name="options">Options that control file operations.</param>
public static void Delete(ShellItem source, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostDeleteItem += OnPost;
try
{
sop.QueueDeleteOperation(source);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostDeleteItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Deletes a set of items using the Shell to provide progress and error dialogs.</summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances which represents the group of items to be deleted.
/// </param>
/// <param name="options">Options that control file operations.</param>
public static void Delete(IEnumerable<ShellItem> sourceItems, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostDeleteItem += OnPost;
try
{
sop.QueueDeleteOperation(sourceItems);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostDeleteItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Moves a single item to a specified destination using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A string that specifies the source item's full file path.</param>
/// <param name="dest">A string that specifies the full path of the destination folder to contain the copy of the item.</param>
/// <param name="newName">
/// An optional new name for the item in its new location. This can be <see langword="null"/>. If <see langword="null"/>, the name
/// of the destination item is the same as the source.
/// </param>
/// <param name="options">Options that control file operations.</param>
public static void Move(string source, string dest, string newName = null, OperationFlags options = defaultOptions)
{
using var shfile = new ShellItem(source);
using var shfld = new ShellFolder(dest);
Move(shfile, shfld, newName, options);
}
/// <summary>Moves a single item to a specified destination using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the source item.</param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the moved item.</param>
/// <param name="newName">
/// An optional new name for the item in its new location. This can be <see langword="null"/>. If <see langword="null"/>, the name
/// of the destination item is the same as the source.
/// </param>
/// <param name="options">Options that control file operations.</param>
public static void Move(ShellItem source, ShellFolder dest, string newName = null, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations { Options = options };
HRESULT hr = HRESULT.S_OK;
sop.PostMoveItem += OnPost;
try
{
sop.QueueMoveOperation(source, dest, newName);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostMoveItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Moves a set of items to a specified destination using the Shell to provide progress and error dialogs.</summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances which represents the group of items to be moved.
/// </param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the moved items.</param>
/// <param name="options">Options that control file operations.</param>
public static void Move(IEnumerable<ShellItem> sourceItems, ShellFolder dest, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostMoveItem += OnPost;
try
{
sop.QueueMoveOperation(sourceItems, dest);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostMoveItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Creates a new item in a specified location using the Shell to provide progress and error dialogs.</summary>
/// <param name="dest">A <see cref="ShellItem"/> that specifies the destination folder that will contain the new item.</param>
/// <param name="name">The file name of the new item, for instance Newfile.txt.</param>
/// <param name="attr">A value that specifies the file system attributes for the file or folder.</param>
/// <param name="template">
/// The name of the template file (for example Excel9.xls) that the new item is based on, stored in one of the following locations:
/// <list type="bullet">
/// <item>
/// <description>CSIDL_COMMON_TEMPLATES. The default path for this folder is %ALLUSERSPROFILE%\Templates.</description>
/// </item>
/// <item>
/// <description>CSIDL_TEMPLATES. The default path for this folder is %USERPROFILE%\Templates.</description>
/// </item>
/// <item>
/// <description>%SystemRoot%\shellnew</description>
/// </item>
/// </list>
/// <para>
/// This is a string used to specify an existing file of the same type as the new file, containing the minimal content that an
/// application wants to include in any new file.
/// </para>
/// <para>This parameter is normally <see langword="null"/> to specify a new, blank file.</para>
/// </param>
/// <param name="options">Options that control file operations.</param>
public static void NewItem(ShellFolder dest, string name, System.IO.FileAttributes attr = System.IO.FileAttributes.Normal, string template = null, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostNewItem += OnPost;
try
{
sop.QueueNewItemOperation(dest, name, attr, template);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostRenameItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Renames a single item to a new display name using the Shell to provide progress and error dialogs.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the source item.</param>
/// <param name="newName">The new display name of the item.</param>
/// <param name="options">Options that control file operations.</param>
public static void Rename(ShellItem source, string newName = null, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostRenameItem += OnPost;
try
{
sop.QueueRenameOperation(source, newName);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostRenameItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>
/// Renames a set of items that are to be given a new display name using the Shell to provide progress and error dialogs. All items
/// are given the same name.
/// </summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances which represents the group of items to be renamed.
/// </param>
/// <param name="newName">The new display name of the items.</param>
/// <param name="options">Options that control file operations.</param>
public static void Rename(IEnumerable<ShellItem> sourceItems, string newName, OperationFlags options = defaultOptions)
{
using var sop = new ShellFileOperations();
sop.Options = options;
HRESULT hr = HRESULT.S_OK;
sop.PostRenameItem += OnPost;
try
{
sop.QueueRenameOperation(sourceItems, newName);
sop.PerformOperations();
hr.ThrowIfFailed();
}
finally
{
sop.PostRenameItem -= OnPost;
}
void OnPost(object sender, ShellFileOpEventArgs e) => hr = e.Result;
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>Executes all selected operations.</summary>
/// <remarks>
/// This method is called last to execute those actions that have been specified earlier by calling their individual methods. For
/// instance, <see cref="QueueRenameOperation(ShellItem, string)"/> does not rename the item, it simply sets the parameters. The
/// actual renaming is done when you call PerformOperations.
/// </remarks>
public void PerformOperations()
{
op.PerformOperations();
QueuedOperations = 0;
}
/// <summary>Declares a set of properties and values to be set on an item.</summary>
/// <param name="item">The item to receive the new property values.</param>
/// <param name="props">
/// An <see cref="ShellItemPropertyUpdates"/>, which contains a dictionary of objects that specify the properties to be set and
/// their new values.
/// </param>
public void QueueApplyPropertiesOperation(ShellItem item, ShellItemPropertyUpdates props)
{
op.SetProperties(props.IPropertyChangeArray);
op.ApplyPropertiesToItem(item.IShellItem);
QueuedOperations++;
}
/// <summary>Declares a set of properties and values to be set on a set of items.</summary>
/// <param name="items">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances that represent the group of items to which to apply the properties.
/// </param>
/// <param name="props">
/// An <see cref="ShellItemPropertyUpdates"/>, which contains a dictionary of objects that specify the properties to be set and
/// their new values.
/// </param>
public void QueueApplyPropertiesOperation(IEnumerable<ShellItem> items, ShellItemPropertyUpdates props)
{
op.SetProperties(props.IPropertyChangeArray);
op.ApplyPropertiesToItems(GetSHArray(items).IShellItemArray);
QueuedOperations++;
}
/// <summary>Declares a single item that is to be copied to a specified destination.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the source item.</param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the copy of the item.</param>
/// <param name="newName">
/// An optional new name for the item after it has been copied. This can be <see langword="null"/>. If <see langword="null"/>, the
/// name of the destination item is the same as the source.
/// </param>
public void QueueCopyOperation(ShellItem source, ShellFolder dest, string newName = null)
{
op.CopyItem(source.IShellItem, dest.IShellItem, newName, null);
QueuedOperations++;
}
/// <summary>Declares a set of items that are to be copied to a specified destination.</summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances that represent the group of items to be copied.
/// </param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the copy of the items.</param>
public void QueueCopyOperation(IEnumerable<ShellItem> sourceItems, ShellFolder dest)
{
op.CopyItems(GetSHArray(sourceItems).IShellItemArray, dest.IShellItem);
QueuedOperations++;
}
/// <summary>Declares a single item that is to be deleted.</summary>
/// <param name="item">&gt;A <see cref="ShellItem"/> that specifies the item to be deleted.</param>
public void QueueDeleteOperation(ShellItem item)
{
op.DeleteItem(item.IShellItem, null);
QueuedOperations++;
}
/// <summary>Declares a set of items that are to be deleted.</summary>
/// <param name="items">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances which represents the group of items to be deleted.
/// </param>
public void QueueDeleteOperation(IEnumerable<ShellItem> items)
{
op.DeleteItems(GetSHArray(items).IShellItemArray);
QueuedOperations++;
}
/// <summary>Declares a single item that is to be moved to a specified destination.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the source item.</param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the moved item.</param>
/// <param name="newName">
/// An optional new name for the item in its new location. This can be <see langword="null"/>. If <see langword="null"/>, the name
/// of the destination item is the same as the source.
/// </param>
public void QueueMoveOperation(ShellItem source, ShellFolder dest, string newName = null)
{
op.MoveItem(source.IShellItem, dest.IShellItem, newName, null);
QueuedOperations++;
}
/// <summary>Declares a set of items that are to be moved to a specified destination.</summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances which represents the group of items to be moved.
/// </param>
/// <param name="dest">A <see cref="ShellFolder"/> that specifies the destination folder to contain the moved items.</param>
public void QueueMoveOperation(IEnumerable<ShellItem> sourceItems, ShellFolder dest)
{
op.MoveItems(GetSHArray(sourceItems).IShellItemArray, dest.IShellItem);
QueuedOperations++;
}
/// <summary>Declares a new item that is to be created in a specified location.</summary>
/// <param name="dest">A <see cref="ShellItem"/> that specifies the destination folder that will contain the new item.</param>
/// <param name="name">The file name of the new item, for instance Newfile.txt.</param>
/// <param name="attr">A value that specifies the file system attributes for the file or folder.</param>
/// <param name="template">
/// The name of the template file (for example Excel9.xls) that the new item is based on, stored in one of the following locations:
/// <list type="bullet">
/// <item>
/// <description>CSIDL_COMMON_TEMPLATES. The default path for this folder is %ALLUSERSPROFILE%\Templates.</description>
/// </item>
/// <item>
/// <description>CSIDL_TEMPLATES. The default path for this folder is %USERPROFILE%\Templates.</description>
/// </item>
/// <item>
/// <description>%SystemRoot%\shellnew</description>
/// </item>
/// </list>
/// <para>
/// This is a string used to specify an existing file of the same type as the new file, containing the minimal content that an
/// application wants to include in any new file.
/// </para>
/// <para>This parameter is normally <see langword="null"/> to specify a new, blank file.</para>
/// </param>
public void QueueNewItemOperation(ShellFolder dest, string name, System.IO.FileAttributes attr = System.IO.FileAttributes.Normal, string template = null)
{
op.NewItem(dest.IShellItem, attr, name, template, null);
QueuedOperations++;
}
/// <summary>Declares a single item that is to be given a new display name.</summary>
/// <param name="source">A <see cref="ShellItem"/> that specifies the source item.</param>
/// <param name="newName">The new display name of the item.</param>
public void QueueRenameOperation(ShellItem source, string newName)
{
op.RenameItem(source.IShellItem, newName, null);
QueuedOperations++;
}
/// <summary>Declares a set of items that are to be given a new display name. All items are given the same name.</summary>
/// <param name="sourceItems">
/// An <see cref="IEnumerable{T}"/> of <see cref="ShellItem"/> instances which represents the group of items to be renamed.
/// </param>
/// <param name="newName">The new display name of the items.</param>
public void QueueRenameOperation(IEnumerable<ShellItem> sourceItems, string newName)
{
op.RenameItems(GetSHArray(sourceItems).IShellItemArray, newName);
QueuedOperations++;
}
/// <summary>Releases unmanaged and - optionally - managed resources.</summary>
/// <param name="disposing">
/// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// Dispose managed state (managed objects).
}
if (sink != null) op.Unadvise(sinkCookie);
op = null;
disposedValue = true;
}
}
private ShellItemArray GetSHArray(IEnumerable<ShellItem> items) => items is ShellItemArray a ? a : new ShellItemArray(items);
private class OpSink : IFileOperationProgressSink
{
private readonly ShellFileOperations parent;
public OpSink(ShellFileOperations ops)
{
parent = ops;
}
public HRESULT FinishOperations(HRESULT hrResult) => CallChkErr(() => parent.FinishOperations?.Invoke(parent, new ShellFileOpEventArgs(0, null, null, null, null, hrResult)));
public HRESULT PauseTimer() => HRESULT.E_NOTIMPL;
public HRESULT PostCopyItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName, HRESULT hrCopy, IShellItem psiNewlyCreated) =>
CallChkErr(() => parent.PostCopyItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, psiDestinationFolder, psiNewlyCreated, pszNewName, hrCopy)));
public HRESULT PostDeleteItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, HRESULT hrDelete, IShellItem psiNewlyCreated) =>
CallChkErr(() => parent.PostDeleteItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, null, psiNewlyCreated, null, hrDelete)));
public HRESULT PostMoveItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName, HRESULT hrMove, IShellItem psiNewlyCreated) =>
CallChkErr(() => parent.PostMoveItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, psiDestinationFolder, psiNewlyCreated, pszNewName, hrMove)));
public HRESULT PostNewItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiDestinationFolder, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName, [MarshalAs(UnmanagedType.LPWStr)] string pszTemplateName, uint dwFileAttributes, HRESULT hrNew, IShellItem psiNewItem) =>
CallChkErr(() => parent.PostNewItem?.Invoke(parent, new ShellFileNewOpEventArgs(dwFlags, null, psiDestinationFolder, psiNewItem, pszNewName, hrNew, pszTemplateName, dwFileAttributes)));
public HRESULT PostRenameItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName, HRESULT hrRename, IShellItem psiNewlyCreated) =>
CallChkErr(() => parent.PostRenameItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, null, psiNewlyCreated, pszNewName, hrRename)));
public HRESULT PreCopyItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName) =>
CallChkErr(() => parent.PreCopyItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, psiDestinationFolder, null, pszNewName)));
public HRESULT PreDeleteItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem) =>
CallChkErr(() => parent.PreDeleteItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem)));
public HRESULT PreMoveItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, IShellItem psiDestinationFolder, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName) =>
CallChkErr(() => parent.PreMoveItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, psiDestinationFolder, null, pszNewName)));
public HRESULT PreNewItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiDestinationFolder, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName) =>
CallChkErr(() => parent.PreNewItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, null, psiDestinationFolder, null, pszNewName)));
public HRESULT PreRenameItem(TRANSFER_SOURCE_FLAGS dwFlags, IShellItem psiItem, [MarshalAs(UnmanagedType.LPWStr)] string pszNewName) => CallChkErr(() => parent.PreRenameItem?.Invoke(parent, new ShellFileOpEventArgs(dwFlags, psiItem, null, null, pszNewName)));
public HRESULT ResetTimer() => HRESULT.E_NOTIMPL;
public HRESULT ResumeTimer() => HRESULT.E_NOTIMPL;
public HRESULT StartOperations() => CallChkErr(() => parent.StartOperations?.Invoke(parent, EventArgs.Empty));
public HRESULT UpdateProgress(uint iWorkTotal, uint iWorkSoFar) => CallChkErr(() => parent.UpdateProgress?.Invoke(parent, new System.ComponentModel.ProgressChangedEventArgs(iWorkTotal == 0 ? 0 : (int)(iWorkSoFar * 100 / iWorkTotal), null)));
private HRESULT CallChkErr(Action action)
{
try { action(); }
catch (COMException comex) { return comex.ErrorCode; }
catch (Win32Exception w32ex) { return new Win32Error(unchecked((uint)w32ex.NativeErrorCode)).ToHRESULT(); }
catch (Exception e)
{
#if !(NET20 || NET35 || NET40)
return e.HResult;
#else
throw e;
#endif
}
return HRESULT.S_OK;
}
}
}
}