public void SetPropsTest2() { const string fn = "test.docx"; var fp = Path.Combine(ShellFolder.Desktop.FileSystemPath, fn); var authors = new[] { "David" }; using (var p = new ShellItemPropertyUpdates { { PROPERTYKEY.System.Author, authors } }) using (var op = new ShellFileOperations()) { op.PostNewItem += HandleEvent; op.QueueNewItemOperation(ShellFolder.Desktop, fn, template: @"C:\Users\dahall\Documents\Custom Office Templates\blank.dotx"); op.QueueApplyPropertiesOperation(new ShellItem(fp), p); op.PerformOperations(); } Assert.That(new ShellItem(fp).Properties[PROPERTYKEY.System.Author], Is.EquivalentTo(authors)); File.Delete(fp); void HandleEvent(object sender, ShellFileOperations.ShellFileOpEventArgs args) { Debug.WriteLine(args); Assert.That(args.Result.Succeeded, Is.True); } }
public void NewItemTest() { var files = new[] { "test.docx", "test.txt", "test.xlsx" }; using (var op = new ShellFileOperations()) { foreach (var file in files) { op.QueueNewItemOperation(ShellFolder.Desktop, file); } op.PostNewItem += HandleEvent; op.PerformOperations(); } foreach (var file in files) { var fn = Path.Combine(@"C:\Users\dahall\Desktop", file); Assert.That(File.Exists(fn), Is.True); File.Delete(fn); } void HandleEvent(object sender, ShellFileOperations.ShellFileOpEventArgs args) { Debug.WriteLine(args); Assert.That(args.Result.Succeeded, Is.True); } }
public static bool Delete(IEnumerable <string> Source, bool PermanentDelete, ProgressChangedEventHandler Progress, EventHandler <ShellFileOperations.ShellFileOpEventArgs> PostDeleteEvent) { try { using (ShellFileOperations Operation = new ShellFileOperations { Options = PermanentDelete ? ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoConfirmation : ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.RecycleOnDelete }) { Operation.UpdateProgress += Progress; Operation.PostDeleteItem += PostDeleteEvent; foreach (string Path in Source) { using (ShellItem Item = new ShellItem(Path)) { Operation.QueueDeleteOperation(Item); } } Operation.PerformOperations(); Operation.PostDeleteItem -= PostDeleteEvent; Operation.UpdateProgress -= Progress; } return(true); } catch { return(false); } }
public static bool Restore(string Path) { try { using (ShellItem SourceItem = new ShellItem(Path)) { string DirectoryName = System.IO.Path.GetDirectoryName(SourceItem.Name); if (!Directory.Exists(DirectoryName)) { _ = Directory.CreateDirectory(DirectoryName); } using (ShellFolder DestItem = new ShellFolder(DirectoryName)) { ShellFileOperations.Move(SourceItem, DestItem, null, ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.RenameOnCollision); } string ExtraInfoPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path), System.IO.Path.GetFileName(Path).Replace("$R", "$I")); if (File.Exists(ExtraInfoPath)) { File.Delete(ExtraInfoPath); } } return(true); } catch { return(false); } }
public void CopyWithProgressTest() { // Setup hidden copy op with progress handler bool progressShown = false; using var op = new ShellFileOperations(); op.Options = ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent; op.UpdateProgress += Op_UpdateProgress; // Run the operation using var shi = new ShellItem(TestCaseSources.LargeFile); op.QueueCopyOperation(shi, ShellFolder.Desktop); op.PerformOperations(); // Asert and clean Assert.IsTrue(progressShown); var dest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Path.GetFileName(TestCaseSources.LargeFile)); File.Delete(dest); void Op_UpdateProgress(object sender, System.ComponentModel.ProgressChangedEventArgs args) { Debug.WriteLine($"{args.UserState}: {args.ProgressPercentage}%"); progressShown = true; } }
public static bool Rename(string Source, string DesireName, EventHandler <ShellFileOperations.ShellFileOpEventArgs> PostRenameEvent) { try { using (ShellFileOperations Operation = new ShellFileOperations { Options = ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.RequireElevation | ShellFileOperations.OperationFlags.RenameOnCollision }) { Operation.PostRenameItem += PostRenameEvent; using (ShellItem Item = new ShellItem(Source)) { Operation.QueueRenameOperation(Item, DesireName); } Operation.PerformOperations(); Operation.PostRenameItem -= PostRenameEvent; } return(true); } catch { return(false); } }
public void MultOpsTest() { using (var op = new ShellFileOperations()) { op.Options |= ShellFileOperations.OperationFlags.NoMinimizeBox; var shi = new ShellItem(@"C:\Users\dahall\Downloads\lubuntu-16.04.2-desktop-amd64.iso"); op.PostCopyItem += HandleEvent; op.QueueCopyOperation(shi, ShellFolder.Desktop); shi = new ShellItem(@"C:\Users\dahall\Desktop\lubuntu-16.04.2-desktop-amd64.iso"); op.QueueMoveOperation(shi, new ShellFolder(KNOWNFOLDERID.FOLDERID_Documents)); op.PostMoveItem += HandleEvent; shi = new ShellItem(@"C:\Users\dahall\Documents\lubuntu-16.04.2-desktop-amd64.iso"); op.QueueRenameOperation(shi, "MuchLongerNameForTheFile.iso"); op.PostRenameItem += HandleEvent; shi = new ShellItem(@"C:\Users\dahall\Documents\MuchLongerNameForTheFile.iso"); op.QueueDeleteOperation(shi); op.PostDeleteItem += HandleEvent; op.PerformOperations(); } void HandleEvent(object sender, ShellFileOperations.ShellFileOpEventArgs args) { Debug.WriteLine(args); Assert.That(args.Result.Succeeded, Is.True); } }
public void CopyItemTest() { ShellFileOperations.Copy(new ShellItem(TestCaseSources.LargeFile), ShellFolder.Desktop); var dest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Path.GetFileName(TestCaseSources.LargeFile)); Assert.That(File.Exists(dest), Is.True); File.Delete(dest); }
public void CopyItemsTest() { var l = Directory.EnumerateFiles(@"C:\Users\dahall\Downloads", "h*.zip").Select(s => new ShellItem(s)).ToList(); ShellFileOperations.Copy(l, ShellFolder.Desktop); foreach (var i in l) { var fn = Path.Combine(@"C:\Users\dahall\Desktop", i.Name); Assert.That(File.Exists(fn), Is.True); File.Delete(fn); } }
public void CopyItemsTest() { var l = Directory.EnumerateFiles(KNOWNFOLDERID.FOLDERID_Downloads.FullPath(), "h*.zip").Select(s => new ShellItem(s)).ToList(); ShellFileOperations.Copy(l, ShellFolder.Desktop); foreach (var i in l) { var fn = Path.Combine(ShellFolder.Desktop.FileSystemPath, i.Name); Assert.That(File.Exists(fn), Is.True); File.Delete(fn); } }
public void MoveItemTest() { // Delete item to Recycle Bin using var tmp = new TempFile(); Assert.That(() => ShellFileOperations.Delete(tmp.FullName), Throws.Nothing); // Find deleted item using var bin = new ShellFolder(KNOWNFOLDERID.FOLDERID_RecycleBinFolder); var item = bin.FirstOrDefault(si => si.Name == tmp.FullName); Assert.NotNull(item); // Restore item using var dest = new ShellFolder(Path.GetDirectoryName(tmp.FullName)); Assert.That(() => ShellFileOperations.Move(item, dest, null, ShellFileOperations.OperationFlags.NoConfirmation), Throws.Nothing); Assert.IsTrue(File.Exists(tmp.FullName)); }
public static bool Move(string SourcePath, string DestinationPath, string NewName = null) { try { using (ShellItem SourceItem = new ShellItem(SourcePath)) using (ShellFolder DestItem = new ShellFolder(DestinationPath)) { ShellFileOperations.Move(SourceItem, DestItem, NewName, ShellFileOperations.OperationFlags.AllowUndo | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent); } return(true); } catch { return(false); } }
public static bool Copy(IEnumerable <KeyValuePair <string, string> > Source, string DestinationPath, ProgressChangedEventHandler Progress, EventHandler <ShellFileOperations.ShellFileOpEventArgs> PostCopyEvent) { try { if (!Directory.Exists(DestinationPath)) { _ = Directory.CreateDirectory(DestinationPath); } ShellFileOperations.OperationFlags Options = Source.All((Item) => Path.GetDirectoryName(Item.Key) == DestinationPath) ? ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.RenameOnCollision : ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent; using (ShellFileOperations Operation = new ShellFileOperations { Options = Options }) { Operation.UpdateProgress += Progress; Operation.PostCopyItem += PostCopyEvent; foreach (KeyValuePair <string, string> SourceInfo in Source) { using (ShellItem SourceItem = new ShellItem(SourceInfo.Key)) using (ShellFolder DestItem = new ShellFolder(DestinationPath)) { Operation.QueueCopyOperation(SourceItem, DestItem, string.IsNullOrEmpty(SourceInfo.Value) ? null : SourceInfo.Value); } } Operation.PerformOperations(); Operation.PostCopyItem -= PostCopyEvent; Operation.UpdateProgress -= Progress; } return(true); } catch { return(false); } }
public static bool Move(IEnumerable <KeyValuePair <string, string> > Source, string DestinationPath, ProgressChangedEventHandler Progress, EventHandler <ShellFileOperations.ShellFileOpEventArgs> PostMoveEvent) { try { if (!Directory.Exists(DestinationPath)) { _ = Directory.CreateDirectory(DestinationPath); } using (ShellFileOperations Operation = new ShellFileOperations { Options = ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.RequireElevation }) { Operation.UpdateProgress += Progress; Operation.PostMoveItem += PostMoveEvent; foreach (KeyValuePair <string, string> SourceInfo in Source) { using (ShellItem SourceItem = new ShellItem(SourceInfo.Key)) using (ShellFolder DestItem = new ShellFolder(DestinationPath)) { Operation.QueueMoveOperation(SourceItem, DestItem, string.IsNullOrEmpty(SourceInfo.Value) ? null : SourceInfo.Value); } } Operation.PerformOperations(); Operation.PostMoveItem -= PostMoveEvent; Operation.UpdateProgress -= Progress; } return(true); } catch { return(false); } }
public static bool Rename(string Source, string DesireName) { try { using (ShellFileOperations Operation = new ShellFileOperations { Options = ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent }) { using (ShellItem Item = new ShellItem(Source)) { Operation.QueueRenameOperation(Item, DesireName); } Operation.PerformOperations(); } return(true); } catch { return(false); } }
public void MultOpsTest() { const string newLargeFile = "MuchLongerNameForTheFile.bin"; using (var op = new ShellFileOperations()) { op.Options |= ShellFileOperations.OperationFlags.NoMinimizeBox; var shi = new ShellItem(TestCaseSources.LargeFile); op.PostCopyItem += HandleEvent; op.QueueCopyOperation(shi, ShellFolder.Desktop); var dest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Path.GetFileName(TestCaseSources.LargeFile)); shi = new ShellItem(dest); op.QueueMoveOperation(shi, new ShellFolder(KNOWNFOLDERID.FOLDERID_Documents)); op.PostMoveItem += HandleEvent; dest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(TestCaseSources.LargeFile)); shi = new ShellItem(dest); op.QueueRenameOperation(shi, newLargeFile); op.PostRenameItem += HandleEvent; dest = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), newLargeFile); shi = new ShellItem(dest); op.QueueDeleteOperation(shi); op.PostDeleteItem += HandleEvent; op.PerformOperations(); }
public void MoveItemTest2() { var tmp = new TempFile(); var winDir = Environment.GetFolderPath(Environment.SpecialFolder.Windows); using ShellFileOperations Operation = new ShellFileOperations { Options = ShellFileOperations.OperationFlags.AddUndoRecord | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent }; Operation.UpdateProgress += Operation_UpdateProgress; Operation.PostMoveItem += Operation_PostMoveItem; using (var fld = new ShellFolder(winDir)) using (var item = new ShellItem(tmp.FullName)) Assert.That(() => Operation.QueueMoveOperation(item, fld), Throws.Nothing); Assert.That(() => Operation.PerformOperations(), Throws.Nothing); var destFile = Path.Combine(winDir, Path.GetFileName(tmp.FullName)); Assert.IsTrue(File.Exists(destFile)); File.Delete(destFile); Operation.PostMoveItem -= Operation_PostMoveItem; Operation.UpdateProgress -= Operation_UpdateProgress;
public void CopyItemTest() { ShellFileOperations.Copy(new ShellItem(@"C:\Users\dahall\Downloads\lubuntu-16.04.2-desktop-amd64.iso"), ShellFolder.Desktop); Assert.That(File.Exists(@"C:\Users\dahall\Desktop\lubuntu-16.04.2-desktop-amd64.iso"), Is.True); File.Delete(@"C:\Users\dahall\Desktop\lubuntu-16.04.2-desktop-amd64.iso"); }
private async Task ParseFileOperationAsync(NamedPipeServerStream connection, Dictionary <string, object> message) { switch (message.Get("fileop", "")) { case "Clipboard": await Win32API.StartSTATask(() => { System.Windows.Forms.Clipboard.Clear(); var fileToCopy = (string)message["filepath"]; var operation = (DataPackageOperation)(long)message["operation"]; var fileList = new System.Collections.Specialized.StringCollection(); fileList.AddRange(fileToCopy.Split('|')); if (operation == DataPackageOperation.Copy) { System.Windows.Forms.Clipboard.SetFileDropList(fileList); } else if (operation == DataPackageOperation.Move) { byte[] moveEffect = new byte[] { 2, 0, 0, 0 }; MemoryStream dropEffect = new MemoryStream(); dropEffect.Write(moveEffect, 0, moveEffect.Length); var data = new System.Windows.Forms.DataObject(); data.SetFileDropList(fileList); data.SetData("Preferred DropEffect", dropEffect); System.Windows.Forms.Clipboard.SetDataObject(data, true); } return(true); }); break; case "DragDrop": var dropPath = (string)message["droppath"]; var result = await Win32API.StartSTATask(() => { var rdo = new RemoteDataObject(System.Windows.Forms.Clipboard.GetDataObject()); foreach (RemoteDataObject.DataPackage package in rdo.GetRemoteData()) { try { if (package.ItemType == RemoteDataObject.StorageType.File) { string directoryPath = Path.GetDirectoryName(dropPath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } string uniqueName = Win32API.GenerateUniquePath(Path.Combine(dropPath, package.Name)); using (FileStream stream = new FileStream(uniqueName, FileMode.CreateNew)) { package.ContentStream.CopyTo(stream); } } else { string directoryPath = Path.Combine(dropPath, package.Name); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } } } finally { package.Dispose(); } } return(true); }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result } }, message.Get("RequestID", (string)null)); break; case "DeleteItem": { var fileToDeletePath = ((string)message["filepath"]).Split('|'); var permanently = (bool)message["permanently"]; var operationID = (string)message["operationID"]; var(succcess, deletedItems, recycledItems) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { op.Options = ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoConfirmation | ShellFileOperations.OperationFlags.NoErrorUI | ShellFileOperations.OperationFlags.EarlyFailure; if (!permanently) { op.Options |= ShellFileOperations.OperationFlags.RecycleOnDelete | ShellFileOperations.OperationFlags.WantNukeWarning; } List <string> deletedItems = new List <string>(); List <string> recycledItems = new List <string>(); for (var i = 0; i < fileToDeletePath.Length; i++) { using var shi = new ShellItem(fileToDeletePath[i]); op.QueueDeleteOperation(shi); } handleTable.SetValue(operationID, false); var deleteTcs = new TaskCompletionSource <bool>(); op.PostDeleteItem += (s, e) => { if (e.Result.Succeeded) { if (!fileToDeletePath.Any(x => x == e.SourceItem.FileSystemPath)) { return; } deletedItems.Add(e.SourceItem.FileSystemPath); if (e.DestItem != null) { recycledItems.Add(e.DestItem.FileSystemPath); } } }; op.FinishOperations += (s, e) => deleteTcs.TrySetResult(e.Result.Succeeded); op.UpdateProgress += async(s, e) => await Win32API.SendMessageAsync(connection, new ValueSet() { { "Progress", e.ProgressPercentage }, { "OperationID", operationID } }); op.UpdateProgress += (s, e) => { if (handleTable.GetValue <bool>(operationID)) { throw new Win32Exception(unchecked ((int)0x80004005)); // E_FAIL, stops operation } }; try { op.PerformOperations(); } catch { deleteTcs.TrySetResult(false); } handleTable.RemoveValue(operationID); return(await deleteTcs.Task && deletedItems.Count == fileToDeletePath.Length, deletedItems, recycledItems); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", succcess }, { "DeletedItems", JsonConvert.SerializeObject(deletedItems) }, { "RecycledItems", JsonConvert.SerializeObject(recycledItems) } }, message.Get("RequestID", (string)null)); } break; case "RenameItem": { var fileToRenamePath = (string)message["filepath"]; var newName = (string)message["newName"]; var operationID = (string)message["operationID"]; var overwriteOnRename = (bool)message["overwrite"]; var(succcess, renamedItems) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { List <string> renamedItems = new List <string>(); op.Options = ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI | ShellFileOperations.OperationFlags.EarlyFailure; op.Options |= !overwriteOnRename ? ShellFileOperations.OperationFlags.RenameOnCollision : 0; using var shi = new ShellItem(fileToRenamePath); op.QueueRenameOperation(shi, newName); handleTable.SetValue(operationID, false); var renameTcs = new TaskCompletionSource <bool>(); op.PostRenameItem += (s, e) => { if (e.Result.Succeeded) { renamedItems.Add($"{Path.Combine(Path.GetDirectoryName(e.SourceItem.FileSystemPath), e.Name)}"); } }; op.FinishOperations += (s, e) => renameTcs.TrySetResult(e.Result.Succeeded); try { op.PerformOperations(); } catch { renameTcs.TrySetResult(false); } handleTable.RemoveValue(operationID); return(await renameTcs.Task && renamedItems.Count == 1, renamedItems); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", succcess }, { "RenamedItems", JsonConvert.SerializeObject(renamedItems) }, }, message.Get("RequestID", (string)null)); } break; case "MoveItem": { var fileToMovePath = ((string)message["filepath"]).Split('|'); var moveDestination = ((string)message["destpath"]).Split('|'); var operationID = (string)message["operationID"]; var overwriteOnMove = (bool)message["overwrite"]; var(succcess, movedItems, movedSources) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { List <string> movedItems = new List <string>(); List <string> movedSources = new List <string>(); op.Options = ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI | ShellFileOperations.OperationFlags.EarlyFailure; op.Options |= !overwriteOnMove ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : ShellFileOperations.OperationFlags.NoConfirmation; for (var i = 0; i < fileToMovePath.Length; i++) { using (ShellItem shi = new ShellItem(fileToMovePath[i])) using (ShellFolder shd = new ShellFolder(Path.GetDirectoryName(moveDestination[i]))) { op.QueueMoveOperation(shi, shd, Path.GetFileName(moveDestination[i])); } } handleTable.SetValue(operationID, false); var moveTcs = new TaskCompletionSource <bool>(); op.PostMoveItem += (s, e) => { if (e.Result.Succeeded) { if (!fileToMovePath.Any(x => x == e.SourceItem.FileSystemPath)) { return; } if (e.DestFolder != null && !string.IsNullOrEmpty(e.Name)) { movedItems.Add($"{Path.Combine(e.DestFolder.FileSystemPath, e.Name)}"); movedSources.Add(e.SourceItem.FileSystemPath); } } }; op.FinishOperations += (s, e) => moveTcs.TrySetResult(e.Result.Succeeded); op.UpdateProgress += async(s, e) => await Win32API.SendMessageAsync(connection, new ValueSet() { { "Progress", e.ProgressPercentage }, { "OperationID", operationID } }); op.UpdateProgress += (s, e) => { if (handleTable.GetValue <bool>(operationID)) { throw new Win32Exception(unchecked ((int)0x80004005)); // E_FAIL, stops operation } }; try { op.PerformOperations(); } catch { moveTcs.TrySetResult(false); } handleTable.RemoveValue(operationID); return(await moveTcs.Task && movedItems.Count == fileToMovePath.Length, movedItems, movedSources); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", succcess }, { "MovedItems", JsonConvert.SerializeObject(movedItems) }, { "MovedSources", JsonConvert.SerializeObject(movedSources) }, }, message.Get("RequestID", (string)null)); } break; case "CopyItem": { var fileToCopyPath = ((string)message["filepath"]).Split('|'); var copyDestination = ((string)message["destpath"]).Split('|'); var operationID = (string)message["operationID"]; var overwriteOnCopy = (bool)message["overwrite"]; var(succcess, copiedItems, copiedSources) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { List <string> copiedItems = new List <string>(); List <string> copiedSources = new List <string>(); op.Options = ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI | ShellFileOperations.OperationFlags.EarlyFailure; op.Options |= !overwriteOnCopy ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : ShellFileOperations.OperationFlags.NoConfirmation; for (var i = 0; i < fileToCopyPath.Length; i++) { using (ShellItem shi = new ShellItem(fileToCopyPath[i])) using (ShellFolder shd = new ShellFolder(Path.GetDirectoryName(copyDestination[i]))) { op.QueueCopyOperation(shi, shd, Path.GetFileName(copyDestination[i])); } } handleTable.SetValue(operationID, false); var copyTcs = new TaskCompletionSource <bool>(); op.PostCopyItem += (s, e) => { if (e.Result.Succeeded) { if (!fileToCopyPath.Any(x => x == e.SourceItem.FileSystemPath)) { return; } if (e.DestFolder != null && !string.IsNullOrEmpty(e.Name)) { copiedItems.Add($"{Path.Combine(e.DestFolder.FileSystemPath, e.Name)}"); copiedSources.Add(e.SourceItem.FileSystemPath); } } }; op.FinishOperations += (s, e) => copyTcs.TrySetResult(e.Result.Succeeded); op.UpdateProgress += async(s, e) => await Win32API.SendMessageAsync(connection, new ValueSet() { { "Progress", e.ProgressPercentage }, { "OperationID", operationID } }); op.UpdateProgress += (s, e) => { if (handleTable.GetValue <bool>(operationID)) { throw new Win32Exception(unchecked ((int)0x80004005)); // E_FAIL, stops operation } }; try { op.PerformOperations(); } catch { copyTcs.TrySetResult(false); } handleTable.RemoveValue(operationID); return(await copyTcs.Task && copiedItems.Count == fileToCopyPath.Length, copiedItems, copiedSources); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", succcess }, { "CopiedItems", JsonConvert.SerializeObject(copiedItems) }, { "CopiedSources", JsonConvert.SerializeObject(copiedSources) }, }, message.Get("RequestID", (string)null)); } break; case "CancelOperation": { var operationID = (string)message["operationID"]; handleTable.SetValue(operationID, true); } break; case "ParseLink": var linkPath = (string)message["filepath"]; try { if (linkPath.EndsWith(".lnk")) { using var link = new ShellLink(linkPath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100)); await Win32API.SendMessageAsync(connection, new ValueSet() { { "TargetPath", link.TargetPath }, { "Arguments", link.Arguments }, { "WorkingDirectory", link.WorkingDirectory }, { "RunAsAdmin", link.RunAsAdministrator }, { "IsFolder", !string.IsNullOrEmpty(link.TargetPath) && link.Target.IsFolder } }, message.Get("RequestID", (string)null)); } else if (linkPath.EndsWith(".url")) { var linkUrl = await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Load(linkPath, 0); ipf.GetUrl(out var retVal); return(retVal); }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "TargetPath", linkUrl }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }, message.Get("RequestID", (string)null)); } } catch (Exception ex) { // Could not parse shortcut Program.Logger.Warn(ex, ex.Message); await Win32API.SendMessageAsync(connection, new ValueSet() { { "TargetPath", null }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }, message.Get("RequestID", (string)null)); } break; case "CreateLink": case "UpdateLink": var linkSavePath = (string)message["filepath"]; var targetPath = (string)message["targetpath"]; if (linkSavePath.EndsWith(".lnk")) { var arguments = (string)message["arguments"]; var workingDirectory = (string)message["workingdir"]; var runAsAdmin = (bool)message["runasadmin"]; using var newLink = new ShellLink(targetPath, arguments, workingDirectory); newLink.RunAsAdministrator = runAsAdmin; newLink.SaveAs(linkSavePath); // Overwrite if exists } else if (linkSavePath.EndsWith(".url")) { await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); ipf.SetUrl(targetPath, Url.IURL_SETURL_FLAGS.IURL_SETURL_FL_GUESS_PROTOCOL); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Save(linkSavePath, false); // Overwrite if exists return(true); }); } break; case "GetFilePermissions": { var filePathForPerm = (string)message["filepath"]; var isFolder = (bool)message["isfolder"]; var filePermissions = FilePermissions.FromFilePath(filePathForPerm, isFolder); await Win32API.SendMessageAsync(connection, new ValueSet() { { "FilePermissions", JsonConvert.SerializeObject(filePermissions) } }, message.Get("RequestID", (string)null)); } break; case "SetFilePermissions": { var filePermissionsString = (string)message["permissions"]; var filePermissionsToSet = JsonConvert.DeserializeObject <FilePermissions>(filePermissionsString); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", filePermissionsToSet.SetPermissions() } }, message.Get("RequestID", (string)null)); } break; case "SetFileOwner": { var filePathForPerm = (string)message["filepath"]; var isFolder = (bool)message["isfolder"]; var ownerSid = (string)message["ownersid"]; var fp = FilePermissions.FromFilePath(filePathForPerm, isFolder); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", fp.SetOwner(ownerSid) } }, message.Get("RequestID", (string)null)); } break; case "SetAccessRuleProtection": { var filePathForPerm = (string)message["filepath"]; var isFolder = (bool)message["isfolder"]; var isProtected = (bool)message["isprotected"]; var preserveInheritance = (bool)message["preserveinheritance"]; var fp = FilePermissions.FromFilePath(filePathForPerm, isFolder); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", fp.SetAccessRuleProtection(isProtected, preserveInheritance) } }, message.Get("RequestID", (string)null)); } break; case "OpenObjectPicker": var hwnd = (long)message["HWND"]; var pickedObject = await FilePermissions.OpenObjectPicker(hwnd); await Win32API.SendMessageAsync(connection, new ValueSet() { { "PickedObject", pickedObject } }, message.Get("RequestID", (string)null)); break; } }
private static async Task parseFileOperation(AppServiceRequestReceivedEventArgs args) { var fileOp = (string)args.Request.Message["fileop"]; switch (fileOp) { case "Clipboard": await Win32API.StartSTATask(() => { System.Windows.Forms.Clipboard.Clear(); var fileToCopy = (string)args.Request.Message["filepath"]; var operation = (DataPackageOperation)(int)args.Request.Message["operation"]; var fileList = new System.Collections.Specialized.StringCollection(); fileList.AddRange(fileToCopy.Split('|')); if (operation == DataPackageOperation.Copy) { System.Windows.Forms.Clipboard.SetFileDropList(fileList); } else if (operation == DataPackageOperation.Move) { byte[] moveEffect = new byte[] { 2, 0, 0, 0 }; MemoryStream dropEffect = new MemoryStream(); dropEffect.Write(moveEffect, 0, moveEffect.Length); var data = new System.Windows.Forms.DataObject(); data.SetFileDropList(fileList); data.SetData("Preferred DropEffect", dropEffect); System.Windows.Forms.Clipboard.SetDataObject(data, true); } return(true); }); break; case "MoveToBin": var fileToDeletePath = (string)args.Request.Message["filepath"]; using (var op = new ShellFileOperations()) { op.Options = ShellFileOperations.OperationFlags.AllowUndo | ShellFileOperations.OperationFlags.NoUI; using var shi = new ShellItem(fileToDeletePath); op.QueueDeleteOperation(shi); op.PerformOperations(); } //ShellFileOperations.Delete(fileToDeletePath, ShellFileOperations.OperationFlags.AllowUndo | ShellFileOperations.OperationFlags.NoUI); break; case "ParseLink": var linkPath = (string)args.Request.Message["filepath"]; try { if (linkPath.EndsWith(".lnk")) { using var link = new ShellLink(linkPath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100)); await args.Request.SendResponseAsync(new ValueSet() { { "TargetPath", link.TargetPath }, { "Arguments", link.Arguments }, { "WorkingDirectory", link.WorkingDirectory }, { "RunAsAdmin", link.RunAsAdministrator }, { "IsFolder", !string.IsNullOrEmpty(link.TargetPath) && link.Target.IsFolder } }); } else if (linkPath.EndsWith(".url")) { var linkUrl = await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Load(linkPath, 0); ipf.GetUrl(out var retVal); return(retVal); }); await args.Request.SendResponseAsync(new ValueSet() { { "TargetPath", linkUrl }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }); } } catch (Exception ex) { // Could not parse shortcut Logger.Warn(ex, ex.Message); await args.Request.SendResponseAsync(new ValueSet() { { "TargetPath", null }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }); } break; case "CreateLink": case "UpdateLink": var linkSavePath = (string)args.Request.Message["filepath"]; var targetPath = (string)args.Request.Message["targetpath"]; if (linkSavePath.EndsWith(".lnk")) { var arguments = (string)args.Request.Message["arguments"]; var workingDirectory = (string)args.Request.Message["workingdir"]; var runAsAdmin = (bool)args.Request.Message["runasadmin"]; using var newLink = new ShellLink(targetPath, arguments, workingDirectory); newLink.RunAsAdministrator = runAsAdmin; newLink.SaveAs(linkSavePath); // Overwrite if exists } else if (linkSavePath.EndsWith(".url")) { await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); ipf.SetUrl(targetPath, Url.IURL_SETURL_FLAGS.IURL_SETURL_FL_GUESS_PROTOCOL); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Save(linkSavePath, false); // Overwrite if exists return(true); }); } break; } }
private async Task ParseFileOperationAsync(PipeStream connection, Dictionary <string, object> message) { switch (message.Get("fileop", "")) { case "GetFileHandle": { var filePath = (string)message["filepath"]; var readWrite = (bool)message["readwrite"]; using var hFile = Kernel32.CreateFile(filePath, Kernel32.FileAccess.GENERIC_READ | (readWrite ? Kernel32.FileAccess.GENERIC_WRITE : 0), FileShare.ReadWrite, null, FileMode.Open, FileFlagsAndAttributes.FILE_ATTRIBUTE_NORMAL); if (hFile.IsInvalid) { await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); return; } var processId = (int)(long)message["processid"]; using var uwpProces = System.Diagnostics.Process.GetProcessById(processId); if (!Kernel32.DuplicateHandle(Kernel32.GetCurrentProcess(), hFile.DangerousGetHandle(), uwpProces.Handle, out var targetHandle, 0, false, Kernel32.DUPLICATE_HANDLE_OPTIONS.DUPLICATE_SAME_ACCESS)) { await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); return; } await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", true }, { "Handle", targetHandle.ToInt64() } }, message.Get("RequestID", (string)null)); } break; case "Clipboard": await Win32API.StartSTATask(() => { System.Windows.Forms.Clipboard.Clear(); var fileToCopy = (string)message["filepath"]; var operation = (DataPackageOperation)(long)message["operation"]; var fileList = new System.Collections.Specialized.StringCollection(); fileList.AddRange(fileToCopy.Split('|')); if (operation == DataPackageOperation.Copy) { System.Windows.Forms.Clipboard.SetFileDropList(fileList); } else if (operation == DataPackageOperation.Move) { byte[] moveEffect = new byte[] { 2, 0, 0, 0 }; MemoryStream dropEffect = new MemoryStream(); dropEffect.Write(moveEffect, 0, moveEffect.Length); var data = new System.Windows.Forms.DataObject(); data.SetFileDropList(fileList); data.SetData("Preferred DropEffect", dropEffect); System.Windows.Forms.Clipboard.SetDataObject(data, true); } return(true); }); break; case "DragDrop": var dropPath = (string)message["droppath"]; var result = await Win32API.StartSTATask(() => { var rdo = new RemoteDataObject(System.Windows.Forms.Clipboard.GetDataObject()); foreach (RemoteDataObject.DataPackage package in rdo.GetRemoteData()) { try { if (package.ItemType == RemoteDataObject.StorageType.File) { string directoryPath = Path.GetDirectoryName(dropPath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } string uniqueName = Win32API.GenerateUniquePath(Path.Combine(dropPath, package.Name)); using (FileStream stream = new FileStream(uniqueName, FileMode.CreateNew)) { package.ContentStream.CopyTo(stream); } } else { string directoryPath = Path.Combine(dropPath, package.Name); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } } } finally { package.Dispose(); } } return(true); }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", result } }, message.Get("RequestID", (string)null)); break; case "CreateFile": case "CreateFolder": { var filePath = (string)message["filepath"]; var template = message.Get("template", (string)null); var dataStr = message.Get("data", (string)null); var(success, shellOperationResult) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { op.Options = ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.RenameOnCollision | ShellFileOperations.OperationFlags.NoErrorUI; var shellOperationResult = new ShellOperationResult(); using var shd = new ShellFolder(Path.GetDirectoryName(filePath)); op.QueueNewItemOperation(shd, Path.GetFileName(filePath), (string)message["fileop"] == "CreateFolder" ? FileAttributes.Directory : FileAttributes.Normal, template); var createTcs = new TaskCompletionSource <bool>(); op.PostNewItem += (s, e) => { shellOperationResult.Items.Add(new ShellOperationItemResult() { Succeeded = e.Result.Succeeded, Destination = e.DestItem?.FileSystemPath, HRresult = (int)e.Result }); }; op.FinishOperations += (s, e) => createTcs.TrySetResult(e.Result.Succeeded); try { op.PerformOperations(); } catch { createTcs.TrySetResult(false); } if (dataStr != null && (shellOperationResult.Items.SingleOrDefault()?.Succeeded ?? false)) { Extensions.IgnoreExceptions(() => { var dataBytes = Convert.FromBase64String(dataStr); using (var fs = new FileStream(shellOperationResult.Items.Single().Destination, FileMode.Open)) { fs.Write(dataBytes, 0, dataBytes.Length); fs.Flush(); } }, Program.Logger); } return(await createTcs.Task, shellOperationResult); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", success }, { "Result", JsonConvert.SerializeObject(shellOperationResult) } }, message.Get("RequestID", (string)null)); } break; case "DeleteItem": { var fileToDeletePath = ((string)message["filepath"]).Split('|'); var permanently = (bool)message["permanently"]; var operationID = (string)message["operationID"]; var ownerHwnd = (long)message["HWND"]; var(success, shellOperationResult) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { op.Options = ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoConfirmation | ShellFileOperations.OperationFlags.NoErrorUI; op.OwnerWindow = Win32API.Win32Window.FromLong(ownerHwnd); if (!permanently) { op.Options |= ShellFileOperations.OperationFlags.RecycleOnDelete | ShellFileOperations.OperationFlags.WantNukeWarning; } var shellOperationResult = new ShellOperationResult(); for (var i = 0; i < fileToDeletePath.Length; i++) { using var shi = new ShellItem(fileToDeletePath[i]); op.QueueDeleteOperation(shi); } progressHandler.OwnerWindow = op.OwnerWindow; progressHandler.AddOperation(operationID); var deleteTcs = new TaskCompletionSource <bool>(); op.PreDeleteItem += (s, e) => { if (!permanently && !e.Flags.HasFlag(ShellFileOperations.TransferFlags.DeleteRecycleIfPossible)) { throw new Win32Exception(HRESULT.COPYENGINE_E_RECYCLE_BIN_NOT_FOUND); // E_FAIL, stops operation } }; op.PostDeleteItem += (s, e) => { shellOperationResult.Items.Add(new ShellOperationItemResult() { Succeeded = e.Result.Succeeded, Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName, Destination = e.DestItem?.FileSystemPath, HRresult = (int)e.Result }); }; op.PostDeleteItem += (s, e) => UpdateFileTageDb(s, e, "delete"); op.FinishOperations += (s, e) => deleteTcs.TrySetResult(e.Result.Succeeded); op.UpdateProgress += (s, e) => { if (progressHandler.CheckCanceled(operationID)) { throw new Win32Exception(unchecked ((int)0x80004005)); // E_FAIL, stops operation } progressHandler.UpdateOperation(operationID, e.ProgressPercentage); }; try { op.PerformOperations(); } catch { deleteTcs.TrySetResult(false); } progressHandler.RemoveOperation(operationID); return(await deleteTcs.Task, shellOperationResult); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", success }, { "Result", JsonConvert.SerializeObject(shellOperationResult) } }, message.Get("RequestID", (string)null)); } break; case "RenameItem": { var fileToRenamePath = (string)message["filepath"]; var newName = (string)message["newName"]; var operationID = (string)message["operationID"]; var overwriteOnRename = (bool)message["overwrite"]; var(success, shellOperationResult) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { var shellOperationResult = new ShellOperationResult(); op.Options = ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI; op.Options |= !overwriteOnRename ? ShellFileOperations.OperationFlags.RenameOnCollision : 0; using var shi = new ShellItem(fileToRenamePath); op.QueueRenameOperation(shi, newName); progressHandler.OwnerWindow = op.OwnerWindow; progressHandler.AddOperation(operationID); var renameTcs = new TaskCompletionSource <bool>(); op.PostRenameItem += (s, e) => { shellOperationResult.Items.Add(new ShellOperationItemResult() { Succeeded = e.Result.Succeeded, Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName, Destination = !string.IsNullOrEmpty(e.Name) ? Path.Combine(Path.GetDirectoryName(e.SourceItem.FileSystemPath), e.Name) : null, HRresult = (int)e.Result }); }; op.PostRenameItem += (s, e) => UpdateFileTageDb(s, e, "rename"); op.FinishOperations += (s, e) => renameTcs.TrySetResult(e.Result.Succeeded); try { op.PerformOperations(); } catch { renameTcs.TrySetResult(false); } progressHandler.RemoveOperation(operationID); return(await renameTcs.Task, shellOperationResult); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", success }, { "Result", JsonConvert.SerializeObject(shellOperationResult) }, }, message.Get("RequestID", (string)null)); } break; case "MoveItem": { var fileToMovePath = ((string)message["filepath"]).Split('|'); var moveDestination = ((string)message["destpath"]).Split('|'); var operationID = (string)message["operationID"]; var overwriteOnMove = (bool)message["overwrite"]; var ownerHwnd = (long)message["HWND"]; var(success, shellOperationResult) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { var shellOperationResult = new ShellOperationResult(); op.Options = ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI; op.OwnerWindow = Win32API.Win32Window.FromLong(ownerHwnd); op.Options |= !overwriteOnMove ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : ShellFileOperations.OperationFlags.NoConfirmation; for (var i = 0; i < fileToMovePath.Length; i++) { using (ShellItem shi = new ShellItem(fileToMovePath[i])) using (ShellFolder shd = new ShellFolder(Path.GetDirectoryName(moveDestination[i]))) { op.QueueMoveOperation(shi, shd, Path.GetFileName(moveDestination[i])); } } progressHandler.OwnerWindow = op.OwnerWindow; progressHandler.AddOperation(operationID); var moveTcs = new TaskCompletionSource <bool>(); op.PostMoveItem += (s, e) => { shellOperationResult.Items.Add(new ShellOperationItemResult() { Succeeded = e.Result.Succeeded, Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName, Destination = e.DestFolder?.FileSystemPath != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null, HRresult = (int)e.Result }); }; op.PostMoveItem += (s, e) => UpdateFileTageDb(s, e, "move"); op.FinishOperations += (s, e) => moveTcs.TrySetResult(e.Result.Succeeded); op.UpdateProgress += (s, e) => { if (progressHandler.CheckCanceled(operationID)) { throw new Win32Exception(unchecked ((int)0x80004005)); // E_FAIL, stops operation } progressHandler.UpdateOperation(operationID, e.ProgressPercentage); }; try { op.PerformOperations(); } catch { moveTcs.TrySetResult(false); } progressHandler.RemoveOperation(operationID); return(await moveTcs.Task, shellOperationResult); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", success }, { "Result", JsonConvert.SerializeObject(shellOperationResult) } }, message.Get("RequestID", (string)null)); } break; case "CopyItem": { var fileToCopyPath = ((string)message["filepath"]).Split('|'); var copyDestination = ((string)message["destpath"]).Split('|'); var operationID = (string)message["operationID"]; var overwriteOnCopy = (bool)message["overwrite"]; var ownerHwnd = (long)message["HWND"]; var(success, shellOperationResult) = await Win32API.StartSTATask(async() => { using (var op = new ShellFileOperations()) { var shellOperationResult = new ShellOperationResult(); op.Options = ShellFileOperations.OperationFlags.NoConfirmMkDir | ShellFileOperations.OperationFlags.Silent | ShellFileOperations.OperationFlags.NoErrorUI; op.OwnerWindow = Win32API.Win32Window.FromLong(ownerHwnd); op.Options |= !overwriteOnCopy ? ShellFileOperations.OperationFlags.PreserveFileExtensions | ShellFileOperations.OperationFlags.RenameOnCollision : ShellFileOperations.OperationFlags.NoConfirmation; for (var i = 0; i < fileToCopyPath.Length; i++) { using (ShellItem shi = new ShellItem(fileToCopyPath[i])) using (ShellFolder shd = new ShellFolder(Path.GetDirectoryName(copyDestination[i]))) { op.QueueCopyOperation(shi, shd, Path.GetFileName(copyDestination[i])); } } progressHandler.OwnerWindow = op.OwnerWindow; progressHandler.AddOperation(operationID); var copyTcs = new TaskCompletionSource <bool>(); op.PostCopyItem += (s, e) => { shellOperationResult.Items.Add(new ShellOperationItemResult() { Succeeded = e.Result.Succeeded, Source = e.SourceItem.FileSystemPath ?? e.SourceItem.ParsingName, Destination = e.DestFolder?.FileSystemPath != null && !string.IsNullOrEmpty(e.Name) ? Path.Combine(e.DestFolder.FileSystemPath, e.Name) : null, HRresult = (int)e.Result }); }; op.PostCopyItem += (s, e) => UpdateFileTageDb(s, e, "copy"); op.FinishOperations += (s, e) => copyTcs.TrySetResult(e.Result.Succeeded); op.UpdateProgress += (s, e) => { if (progressHandler.CheckCanceled(operationID)) { throw new Win32Exception(unchecked ((int)0x80004005)); // E_FAIL, stops operation } progressHandler.UpdateOperation(operationID, e.ProgressPercentage); }; try { op.PerformOperations(); } catch { copyTcs.TrySetResult(false); } progressHandler.RemoveOperation(operationID); return(await copyTcs.Task, shellOperationResult); } }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", success }, { "Result", JsonConvert.SerializeObject(shellOperationResult) } }, message.Get("RequestID", (string)null)); } break; case "CancelOperation": { var operationID = (string)message["operationID"]; progressHandler.TryCancel(operationID); } break; case "ParseLink": try { var linkPath = (string)message["filepath"]; if (linkPath.EndsWith(".lnk")) { using var link = new ShellLink(linkPath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100)); await Win32API.SendMessageAsync(connection, new ValueSet() { { "TargetPath", link.TargetPath }, { "Arguments", link.Arguments }, { "WorkingDirectory", link.WorkingDirectory }, { "RunAsAdmin", link.RunAsAdministrator }, { "IsFolder", !string.IsNullOrEmpty(link.TargetPath) && link.Target.IsFolder } }, message.Get("RequestID", (string)null)); } else if (linkPath.EndsWith(".url")) { var linkUrl = await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Load(linkPath, 0); ipf.GetUrl(out var retVal); return(retVal); }); await Win32API.SendMessageAsync(connection, new ValueSet() { { "TargetPath", linkUrl }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }, message.Get("RequestID", (string)null)); } } catch (Exception ex) { // Could not parse shortcut Program.Logger.Warn(ex, ex.Message); await Win32API.SendMessageAsync(connection, new ValueSet() { { "TargetPath", null }, { "Arguments", null }, { "WorkingDirectory", null }, { "RunAsAdmin", false }, { "IsFolder", false } }, message.Get("RequestID", (string)null)); } break; case "CreateLink": case "UpdateLink": try { var linkSavePath = (string)message["filepath"]; var targetPath = (string)message["targetpath"]; bool success = false; if (linkSavePath.EndsWith(".lnk")) { var arguments = (string)message["arguments"]; var workingDirectory = (string)message["workingdir"]; var runAsAdmin = (bool)message["runasadmin"]; using var newLink = new ShellLink(targetPath, arguments, workingDirectory); newLink.RunAsAdministrator = runAsAdmin; newLink.SaveAs(linkSavePath); // Overwrite if exists success = true; } else if (linkSavePath.EndsWith(".url")) { success = await Win32API.StartSTATask(() => { var ipf = new Url.IUniformResourceLocator(); ipf.SetUrl(targetPath, Url.IURL_SETURL_FLAGS.IURL_SETURL_FL_GUESS_PROTOCOL); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Save(linkSavePath, false); // Overwrite if exists return(true); }); } await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", success } }, message.Get("RequestID", (string)null)); } catch (Exception ex) { // Could not create shortcut Program.Logger.Warn(ex, ex.Message); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); } break; case "SetLinkIcon": try { var linkPath = (string)message["filepath"]; using var link = new ShellLink(linkPath, LinkResolution.NoUIWithMsgPump, null, TimeSpan.FromMilliseconds(100)); link.IconLocation = new IconLocation((string)message["iconFile"], (int)message.Get("iconIndex", 0L)); link.SaveAs(linkPath); // Overwrite if exists await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", true } }, message.Get("RequestID", (string)null)); } catch (Exception ex) { // Could not create shortcut Program.Logger.Warn(ex, ex.Message); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", false } }, message.Get("RequestID", (string)null)); } break; case "GetFilePermissions": { var filePathForPerm = (string)message["filepath"]; var isFolder = (bool)message["isfolder"]; var filePermissions = FilePermissions.FromFilePath(filePathForPerm, isFolder); await Win32API.SendMessageAsync(connection, new ValueSet() { { "FilePermissions", JsonConvert.SerializeObject(filePermissions) } }, message.Get("RequestID", (string)null)); } break; case "SetFilePermissions": { var filePermissionsString = (string)message["permissions"]; var filePermissionsToSet = JsonConvert.DeserializeObject <FilePermissions>(filePermissionsString); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", filePermissionsToSet.SetPermissions() } }, message.Get("RequestID", (string)null)); } break; case "SetFileOwner": { var filePathForPerm = (string)message["filepath"]; var isFolder = (bool)message["isfolder"]; var ownerSid = (string)message["ownersid"]; var fp = FilePermissions.FromFilePath(filePathForPerm, isFolder); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", fp.SetOwner(ownerSid) } }, message.Get("RequestID", (string)null)); } break; case "SetAccessRuleProtection": { var filePathForPerm = (string)message["filepath"]; var isFolder = (bool)message["isfolder"]; var isProtected = (bool)message["isprotected"]; var preserveInheritance = (bool)message["preserveinheritance"]; var fp = FilePermissions.FromFilePath(filePathForPerm, isFolder); await Win32API.SendMessageAsync(connection, new ValueSet() { { "Success", fp.SetAccessRuleProtection(isProtected, preserveInheritance) } }, message.Get("RequestID", (string)null)); } break; case "OpenObjectPicker": var hwnd = (long)message["HWND"]; var pickedObject = await FilePermissions.OpenObjectPicker(hwnd); await Win32API.SendMessageAsync(connection, new ValueSet() { { "PickedObject", pickedObject } }, message.Get("RequestID", (string)null)); break; case "ReadCompatOptions": { var filePath = (string)message["filepath"]; var compatOptions = Extensions.IgnoreExceptions(() => { using var compatKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"); if (compatKey == null) { return(null); } return((string)compatKey.GetValue(filePath, null)); }, Program.Logger); await Win32API.SendMessageAsync(connection, new ValueSet() { { "CompatOptions", compatOptions } }, message.Get("RequestID", (string)null)); } break; case "SetCompatOptions": { var filePath = (string)message["filepath"]; var compatOptions = (string)message["options"]; bool success = false; if (string.IsNullOrEmpty(compatOptions) || compatOptions == "~") { success = Win32API.RunPowershellCommand(@$ "Remove-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers' -Name '{filePath}' | Out-Null", false); } else { success = Win32API.RunPowershellCommand(@$ "New-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers' -Name '{filePath}' -Value '{compatOptions}' -PropertyType String -Force | Out-Null", false);