diff --git a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs index f50de4bbad35..01df95e5a916 100644 --- a/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs +++ b/src/Files.App.Storage/Windows/Helpers/WindowsStorableHelpers.Icon.cs @@ -29,7 +29,7 @@ public static partial class WindowsStorableHelpers { HRESULT hr = storable.TryGetThumbnail(size, options, out var thumbnailData).ThrowIfFailedOnDebug(); return thumbnailData; - }); + }, null); } /// diff --git a/src/Files.App.Storage/Windows/Managers/STATask.cs b/src/Files.App.Storage/Windows/Managers/STATask.cs index 742e856e3a84..3d968fe6beb3 100644 --- a/src/Files.App.Storage/Windows/Managers/STATask.cs +++ b/src/Files.App.Storage/Windows/Managers/STATask.cs @@ -7,11 +7,17 @@ namespace Files.App.Storage { /// - /// Represents a synchronous/asynchronous operation on STA. + /// Represents a work scheduled to execute on a STA thread. /// public partial class STATask { - public static Task Run(Action action, ILogger? logger = null) + /// + /// Schedules the specified work to execute in a new background thread initialized with STA state. + /// + /// The work to execute in the STA thread. + /// A logger to capture any exception that occurs during execution. + /// A that represents the work scheduled to execute in the STA thread. + public static Task Run(Action action, ILogger? logger) { var tcs = new TaskCompletionSource(); @@ -29,7 +35,6 @@ public static Task Run(Action action, ILogger? logger = null) { tcs.SetResult(); logger?.LogWarning(ex, "An exception was occurred during the execution within STA."); - tcs.SetException(ex); } finally { @@ -44,7 +49,14 @@ public static Task Run(Action action, ILogger? logger = null) return tcs.Task; } - public static Task Run(Func func, ILogger? logger = null) + /// + /// Schedules the specified work to execute in a new background thread initialized with STA state. + /// + /// The type of the result returned by the function. + /// The work to execute in the STA thread. + /// A logger to capture any exception that occurs during execution. + /// A that represents the work scheduled to execute in the STA thread. + public static Task Run(Func func, ILogger? logger) { var tcs = new TaskCompletionSource(); @@ -61,7 +73,6 @@ public static Task Run(Func func, ILogger? logger = null) { tcs.SetResult(default!); logger?.LogWarning(ex, "An exception was occurred during the execution within STA."); - tcs.SetException(ex); } finally { @@ -76,7 +87,13 @@ public static Task Run(Func func, ILogger? logger = null) return tcs.Task; } - public static Task Run(Func func, ILogger? logger = null) + /// + /// Schedules the specified work to execute in a new background thread initialized with STA state. + /// + /// The work to execute in the STA thread. + /// A logger to capture any exception that occurs during execution. + /// A that represents the work scheduled to execute in the STA thread. + public static Task Run(Func func, ILogger? logger) { var tcs = new TaskCompletionSource(); @@ -94,7 +111,6 @@ public static Task Run(Func func, ILogger? logger = null) { tcs.SetResult(); logger?.LogWarning(ex, "An exception was occurred during the execution within STA."); - tcs.SetException(ex); } finally { @@ -109,7 +125,14 @@ public static Task Run(Func func, ILogger? logger = null) return tcs.Task; } - public static Task Run(Func> func, ILogger? logger = null) + /// + /// Schedules the specified work to execute in a new background thread initialized with STA state. + /// + /// The type of the result returned by the function. + /// The work to execute in the STA thread. + /// A logger to capture any exception that occurs during execution. + /// A that represents the work scheduled to execute in the STA thread. + public static Task Run(Func> func, ILogger? logger) { var tcs = new TaskCompletionSource(); @@ -126,7 +149,6 @@ public static Task Run(Func func, ILogger? logger = null) { tcs.SetResult(default); logger?.LogWarning(ex, "An exception was occurred during the execution within STA."); - tcs.SetException(ex); } finally { diff --git a/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs b/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs index c5892a8a1953..6d66875d7189 100644 --- a/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs +++ b/src/Files.App/Helpers/Win32/Win32Helper.Shell.cs @@ -24,7 +24,7 @@ public static partial class Win32Helper path = $"shell:{path}"; } - return await Win32Helper.StartSTATask(() => + return await STATask.Run(() => { var flc = new List(); var folder = (ShellFileItem)null; @@ -77,7 +77,7 @@ public static partial class Win32Helper } return (folder, flc); - }); + }, App.Logger); } public static string GetFolderFromKnownFolderGUID(Guid guid) diff --git a/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs b/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs index 51bc82a35a73..afdf1cc4a042 100644 --- a/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs +++ b/src/Files.App/Helpers/Win32/Win32Helper.Storage.cs @@ -26,143 +26,6 @@ namespace Files.App.Helpers /// public static partial class Win32Helper { - public static Task StartSTATask(Func func) - { - var taskCompletionSource = new TaskCompletionSource(); - Thread thread = new Thread(async () => - { - Ole32.OleInitialize(); - - try - { - await func(); - taskCompletionSource.SetResult(); - } - catch (Exception ex) - { - taskCompletionSource.SetResult(); - App.Logger.LogWarning(ex, ex.Message); - } - finally - { - Ole32.OleUninitialize(); - } - }) - - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - public static Task StartSTATask(Action action) - { - var taskCompletionSource = new TaskCompletionSource(); - Thread thread = new Thread(() => - { - Ole32.OleInitialize(); - - try - { - action(); - taskCompletionSource.SetResult(); - } - catch (Exception ex) - { - taskCompletionSource.SetResult(); - App.Logger.LogWarning(ex, ex.Message); - } - finally - { - Ole32.OleUninitialize(); - } - }) - - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - public static Task StartSTATask(Func func) - { - var taskCompletionSource = new TaskCompletionSource(); - - Thread thread = new Thread(() => - { - Ole32.OleInitialize(); - - try - { - taskCompletionSource.SetResult(func()); - } - catch (Exception ex) - { - taskCompletionSource.SetResult(default); - App.Logger.LogWarning(ex, ex.Message); - //tcs.SetException(e); - } - finally - { - Ole32.OleUninitialize(); - } - }) - - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - - public static Task StartSTATask(Func> func) - { - var taskCompletionSource = new TaskCompletionSource(); - - Thread thread = new Thread(async () => - { - Ole32.OleInitialize(); - try - { - taskCompletionSource.SetResult(await func()); - } - catch (Exception ex) - { - taskCompletionSource.SetResult(default); - App.Logger.LogInformation(ex, ex.Message); - //tcs.SetException(e); - } - finally - { - Ole32.OleUninitialize(); - } - }) - - { - IsBackground = true, - Priority = ThreadPriority.Normal - }; - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - return taskCompletionSource.Task; - } - public static async Task GetFileAssociationAsync(string filename, bool checkDesktopFirst = false) { // Find UWP apps diff --git a/src/Files.App/Services/Storage/StorageNetworkService.cs b/src/Files.App/Services/Storage/StorageNetworkService.cs index 5cea00e864a1..b745565a3b79 100644 --- a/src/Files.App/Services/Storage/StorageNetworkService.cs +++ b/src/Files.App/Services/Storage/StorageNetworkService.cs @@ -91,7 +91,7 @@ public async Task> GetComputersAsync() /// public async Task> GetShortcutsAsync() { - var networkLocations = await Win32Helper.StartSTATask(() => + var networkLocations = await STATask.Run(() => { var locations = new List(); using (var netHood = new ShellFolder(Shell32.KNOWNFOLDERID.FOLDERID_NetHood)) @@ -114,7 +114,7 @@ public async Task> GetShortcutsAsync() } } return locations; - }); + }, App.Logger); return (networkLocations ?? Enumerable.Empty()).Select(item => { @@ -192,13 +192,13 @@ public bool DisconnectNetworkDrive(IFolder drive) /// public Task OpenMapNetworkDriveDialogAsync() { - return Win32Helper.StartSTATask(() => + return STATask.Run(() => { return CommonDialogService.Open_NetworkConnectionDialog( MainWindow.Instance.WindowHandle, useMostRecentPath: true, hideRestoreConnectionCheckBox: false); - }); + }, App.Logger); } /// diff --git a/src/Files.App/Services/Storage/StorageTrashBinService.cs b/src/Files.App/Services/Storage/StorageTrashBinService.cs index 41fb69f46e56..f2feafa3620f 100644 --- a/src/Files.App/Services/Storage/StorageTrashBinService.cs +++ b/src/Files.App/Services/Storage/StorageTrashBinService.cs @@ -83,7 +83,7 @@ public bool EmptyTrashBin() /// public async Task RestoreAllTrashesAsync() { - return await Win32Helper.StartSTATask(() => + return await STATask.Run(() => { try { @@ -95,7 +95,7 @@ public async Task RestoreAllTrashesAsync() { return false; } - }); + }, App.Logger); } private unsafe bool RestoreAllTrashesInternal() diff --git a/src/Files.App/Services/Windows/WindowsQuickAccessService.cs b/src/Files.App/Services/Windows/WindowsQuickAccessService.cs index b060f123a4d0..8c1c1438820f 100644 --- a/src/Files.App/Services/Windows/WindowsQuickAccessService.cs +++ b/src/Files.App/Services/Windows/WindowsQuickAccessService.cs @@ -63,20 +63,20 @@ private async Task UnpinFromSidebarAsync(string[] folderPaths, bool doUpdateQuic (folderPaths.Contains(path) || (path.StartsWith(@"\\SHELL\\") && folderPaths.Any(x => x.StartsWith(@"\\SHELL\\"))))) { - await Win32Helper.StartSTATask(async () => + await STATask.Run(async () => { fi.InvokeVerb("unpinfromhome"); - }); + }, App.Logger); continue; } } if (folderPaths.Contains(pathStr)) { - await Win32Helper.StartSTATask(async () => + await STATask.Run(async () => { fi.InvokeVerb("unpinfromhome"); - }); + }, App.Logger); } } diff --git a/src/Files.App/Utils/Library/LibraryManager.cs b/src/Files.App/Utils/Library/LibraryManager.cs index a3520eb6122b..730a14e5ff62 100644 --- a/src/Files.App/Utils/Library/LibraryManager.cs +++ b/src/Files.App/Utils/Library/LibraryManager.cs @@ -67,7 +67,7 @@ private void InitializeWatcher() /// List of library items public static async Task> ListUserLibraries() { - var libraries = await Win32Helper.StartSTATask(() => + var libraries = await STATask.Run(() => { try { @@ -90,7 +90,7 @@ public static async Task> ListUserLibraries() } return []; - }); + }, App.Logger); return libraries.Select(lib => new LibraryLocationItem(lib)).ToList(); } @@ -134,7 +134,7 @@ public async Task CreateNewLibrary(string name) if (string.IsNullOrWhiteSpace(name) || !CanCreateLibrary(name).result) return false; - var newLib = new LibraryLocationItem(await Win32Helper.StartSTATask(() => + var newLib = new LibraryLocationItem(await STATask.Run(() => { try { @@ -150,7 +150,7 @@ public async Task CreateNewLibrary(string name) } return Task.FromResult(null); - })); + }, App.Logger)); if (newLib is not null) { @@ -178,7 +178,7 @@ public async Task UpdateLibrary(string libraryPath, string // Nothing to update return null; - var item = await Win32Helper.StartSTATask(() => + var item = await STATask.Run(() => { try { @@ -231,7 +231,7 @@ public async Task UpdateLibrary(string libraryPath, string } return Task.FromResult(null); - }); + }, App.Logger); var newLib = item is not null ? new LibraryLocationItem(item) : null; if (newLib is not null) diff --git a/src/Files.App/Utils/Shell/LaunchHelper.cs b/src/Files.App/Utils/Shell/LaunchHelper.cs index b00fac7c6380..879ae0cc809a 100644 --- a/src/Files.App/Utils/Shell/LaunchHelper.cs +++ b/src/Files.App/Utils/Shell/LaunchHelper.cs @@ -141,7 +141,7 @@ private static async Task HandleApplicationLaunch(string application, stri { try { - var opened = await Win32Helper.StartSTATask(async () => + var opened = await STATask.Run(async () => { var split = application.Split('|').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => GetMtpPath(x)); if (split.Count() == 1) @@ -171,13 +171,13 @@ private static async Task HandleApplicationLaunch(string application, stri } return true; - }); + }, App.Logger); if (!opened) { if (application.StartsWith(@"\\SHELL\", StringComparison.Ordinal)) { - opened = await Win32Helper.StartSTATask(async () => + opened = await STATask.Run(async () => { using var cMenu = await ContextMenu.GetContextMenuForFiles(new[] { application }, PInvoke.CMF_DEFAULTONLY); @@ -185,7 +185,7 @@ private static async Task HandleApplicationLaunch(string application, stri await cMenu.InvokeItem(cMenu.Items.FirstOrDefault()?.ID ?? -1); return true; - }); + }, App.Logger); } } diff --git a/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs b/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs index 72a838089f47..ffbd9a9d975c 100644 --- a/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs +++ b/src/Files.App/Utils/Storage/Helpers/FileThumbnailHelper.cs @@ -14,7 +14,7 @@ public static class FileThumbnailHelper { var size = iconOptions.HasFlag(IconOptions.UseCurrentScale) ? requestedSize * App.AppModel.AppWindowDPI : requestedSize; - return await Win32Helper.StartSTATask(() => Win32Helper.GetIcon(path, (int)size, isFolder, iconOptions)); + return await STATask.Run(() => Win32Helper.GetIcon(path, (int)size, isFolder, iconOptions), App.Logger); } /// @@ -24,7 +24,7 @@ public static class FileThumbnailHelper /// /// public static async Task GetIconOverlayAsync(string path, bool isFolder) - => await Win32Helper.StartSTATask(() => Win32Helper.GetIconOverlay(path, isFolder)); + => await STATask.Run(() => Win32Helper.GetIconOverlay(path, isFolder), App.Logger); [Obsolete] public static async Task LoadIconFromPathAsync(string filePath, uint thumbnailSize, ThumbnailMode thumbnailMode, ThumbnailOptions thumbnailOptions, bool isFolder = false) diff --git a/src/Files.App/Utils/Storage/Operations/FileOperationsHelpers.cs b/src/Files.App/Utils/Storage/Operations/FileOperationsHelpers.cs index 870a8d2563ad..0c55158115c8 100644 --- a/src/Files.App/Utils/Storage/Operations/FileOperationsHelpers.cs +++ b/src/Files.App/Utils/Storage/Operations/FileOperationsHelpers.cs @@ -25,7 +25,7 @@ public sealed partial class FileOperationsHelpers public static Task SetClipboard(string[] filesToCopy, DataPackageOperation operation) { - return Win32Helper.StartSTATask(() => + return STATask.Run(() => { System.Windows.Forms.Clipboard.Clear(); var fileList = new System.Collections.Specialized.StringCollection(); @@ -36,12 +36,12 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera data.SetFileDropList(fileList); data.SetData("Preferred DropEffect", dropEffect); System.Windows.Forms.Clipboard.SetDataObject(data, true); - }); + }, App.Logger); } public static Task<(bool, ShellOperationResult)> CreateItemAsync(string filePath, string fileOp, long ownerHwnd, bool asAdmin, string template = "", byte[]? dataBytes = null) { - return Win32Helper.StartSTATask(async () => + return STATask.Run(async () => { using var op = new ShellFileOperations2(); @@ -105,12 +105,12 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera } return (await createTcs.Task, shellOperationResult); - }); + }, App.Logger); } public static Task<(bool, ShellOperationResult)> TestRecycleAsync(string[] fileToDeletePath) { - return Win32Helper.StartSTATask(async () => + return STATask.Run(async () => { using var op = new ShellFileOperations2(); @@ -193,7 +193,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera } return (await deleteTcs.Task, shellOperationResult); - }); + }, App.Logger); } public static Task<(bool, ShellOperationResult)> DeleteItemAsync(string[] fileToDeletePath, bool permanently, long ownerHwnd, bool asAdmin, IProgress progress, string operationID = "") @@ -219,7 +219,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera fsProgress.Report(); progressHandler ??= new(); - return Win32Helper.StartSTATask(async () => + return STATask.Run(async () => { using var op = new ShellFileOperations2(); @@ -324,7 +324,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera cts.Cancel(); return (await deleteTcs.Task, shellOperationResult); - }); + }, App.Logger); } public static Task<(bool, ShellOperationResult)> RenameItemAsync(string fileToRenamePath, string newName, bool overwriteOnRename, long ownerHwnd, bool asAdmin, string operationID = "") @@ -333,7 +333,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera progressHandler ??= new(); - return Win32Helper.StartSTATask(async () => + return STATask.Run(async () => { using var op = new ShellFileOperations2(); var shellOperationResult = new ShellOperationResult(); @@ -391,7 +391,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera progressHandler.RemoveOperation(operationID); return (await renameTcs.Task, shellOperationResult); - }); + }, App.Logger); } public static Task<(bool, ShellOperationResult)> MoveItemAsync(string[] fileToMovePath, string[] moveDestination, bool overwriteOnMove, long ownerHwnd, bool asAdmin, IProgress progress, string operationID = "") @@ -417,7 +417,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera fsProgress.Report(); progressHandler ??= new(); - return Win32Helper.StartSTATask(async () => + return STATask.Run(async () => { using var op = new ShellFileOperations2(); var shellOperationResult = new ShellOperationResult(); @@ -519,7 +519,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera cts.Cancel(); return (await moveTcs.Task, shellOperationResult); - }); + }, App.Logger); } public static Task<(bool, ShellOperationResult)> CopyItemAsync(string[] fileToCopyPath, string[] copyDestination, bool overwriteOnCopy, long ownerHwnd, bool asAdmin, IProgress progress, string operationID = "") @@ -545,7 +545,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera fsProgress.Report(); progressHandler ??= new(); - return Win32Helper.StartSTATask(async () => + return STATask.Run(async () => { using var op = new ShellFileOperations2(); @@ -650,7 +650,7 @@ public static Task SetClipboard(string[] filesToCopy, DataPackageOperation opera cts.Cancel(); return (await copyTcs.Task, shellOperationResult); - }); + }, App.Logger); } public static void TryCancelOperation(string operationId) @@ -696,13 +696,13 @@ public static void TryCancelOperation(string operationId) } else if (FileExtensionHelpers.IsWebLinkFile(linkPath)) { - targetPath = await Win32Helper.StartSTATask(() => + targetPath = await STATask.Run(() => { var ipf = new Url.IUniformResourceLocator(); (ipf as System.Runtime.InteropServices.ComTypes.IPersistFile).Load(linkPath, 0); ipf.GetUrl(out var retVal); return retVal; - }); + }, App.Logger); return string.IsNullOrEmpty(targetPath) ? new ShellLinkItem { @@ -751,13 +751,13 @@ public static Task CreateOrUpdateLinkAsync(string linkSavePath, string tar } else if (FileExtensionHelpers.IsWebLinkFile(linkSavePath)) { - return Win32Helper.StartSTATask(() => + return STATask.Run(() => { 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; - }); + }, App.Logger); } } catch (UnauthorizedAccessException ex) @@ -826,7 +826,7 @@ public static bool SetLinkIcon(string filePath, string iconFile, int iconIndex) public static Task OpenObjectPickerAsync(long hWnd) { - return Win32Helper.StartSTATask(() => + return STATask.Run(() => { var picker = new DirectoryObjectPickerDialog() { @@ -855,7 +855,7 @@ public static bool SetLinkIcon(string filePath, string iconFile, int iconIndex) } return null; - }); + }, App.Logger); } private static ShellItem? GetFirstFile(ShellItem shi) diff --git a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs index 4e83dcadd5eb..87d9b1b23086 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs @@ -216,7 +216,7 @@ public override async Task ExecutePinToSidebarCommand(WidgetCardItem? item) // NOTE: "pintohome" is an undocumented verb, which calls an undocumented COM class, windows.storage.dll!CPinToFrequentExecute : public IExecuteCommand, ... return windowsFile.TryInvokeContextMenuVerb("pintohome"); } - }); + }, App.Logger); if (hr.ThrowIfFailedOnDebug().Failed) return; @@ -253,7 +253,7 @@ public override async Task ExecuteUnpinFromSidebarCommand(WidgetCardItem? item) // NOTE: "remove" is for some shell folders where the "unpinfromhome" may not work return windowsFile.TryInvokeContextMenuVerbs(["unpinfromhome", "remove"], true); } - }); + }, App.Logger); if (hr.ThrowIfFailedOnDebug().Failed) return;