From 860a95a6ad0a8025fc6fe9c3c61c933d16aaf476 Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:15:25 +0000 Subject: [PATCH] Reliability: Handle COM and other exceptions in file dialog services --- .../Services/Windows/WindowsDialogService.cs | 86 +++++++++++++++---- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/src/Files.App/Services/Windows/WindowsDialogService.cs b/src/Files.App/Services/Windows/WindowsDialogService.cs index 57b16c37e0fe..20612523bd0a 100644 --- a/src/Files.App/Services/Windows/WindowsDialogService.cs +++ b/src/Files.App/Services/Windows/WindowsDialogService.cs @@ -23,7 +23,14 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[] try { using ComPtr pDialog = default; - HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileOpenDialog, null, CLSCTX.CLSCTX_INPROC_SERVER).ThrowOnFailure(); + HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileOpenDialog, null, CLSCTX.CLSCTX_INPROC_SERVER); + + // Handle COM creation failure gracefully + if (hr.Failed) + { + App.Logger.LogError("Failed to create IFileOpenDialog COM object. HRESULT: 0x{0:X8}", hr.Value); + return false; + } if (filters.Length is not 0 && filters.Length % 2 is 0) { @@ -52,24 +59,38 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[] pszDefaultFolderPath, null, IID.IID_IShellItem, - (void**)pDefaultFolderShellItem.GetAddressOf()) - .ThrowOnFailure(); + (void**)pDefaultFolderShellItem.GetAddressOf()); + + // Handle shell item creation failure gracefully + if (hr.Failed) + { + App.Logger.LogWarning("Failed to create shell item for default folder '{0}'. HRESULT: 0x{1:X8}. Dialog will open without default folder.", Environment.GetFolderPath(defaultFolder), hr.Value); + // Continue without setting default folder rather than failing completely + } } // Folder picker if (pickFoldersOnly) pDialog.Get()->SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS); - // Set the default folder to open in the dialog - pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get()); - pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get()); + // Set the default folder to open in the dialog (only if creation succeeded) + if (pDefaultFolderShellItem.Get() is not null) + { + pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get()); + pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get()); + } // Show the dialog hr = pDialog.Get()->Show(new HWND(hWnd)); if (hr.Value == unchecked((int)0x800704C7)) // HRESULT_FROM_WIN32(ERROR_CANCELLED) return false; - hr.ThrowOnFailure(); + // Handle dialog show failure gracefully + if (hr.Failed) + { + App.Logger.LogError("Failed to show FileSaveDialog. HRESULT: 0x{0:X8}", hr.Value); + return false; + } // Get the file that user chose using ComPtr pResultShellItem = default; @@ -81,10 +102,14 @@ public unsafe bool Open_FileOpenDialog(nint hWnd, bool pickFoldersOnly, string[] return true; } + catch (COMException comEx) + { + App.Logger.LogError(comEx, "COM failure while opening FileOpenDialog. HRESULT: 0x{0:X8}", comEx.HResult); + return false; + } catch (Exception ex) { - App.Logger.LogError(ex, "Failed to open FileOpenDialog."); - + App.Logger.LogError(ex, "Unexpected error while opening FileOpenDialog."); return false; } } @@ -97,7 +122,14 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[] try { using ComPtr pDialog = default; - HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileSaveDialog, null, CLSCTX.CLSCTX_INPROC_SERVER).ThrowOnFailure(); + HRESULT hr = pDialog.CoCreateInstance(CLSID.CLSID_FileSaveDialog, null, CLSCTX.CLSCTX_INPROC_SERVER); + + // Handle COM creation failure gracefully + if (hr.Failed) + { + App.Logger.LogError("Failed to create IFileSaveDialog COM object. HRESULT: 0x{0:X8}", hr.Value); + return false; + } if (filters.Length is not 0 && filters.Length % 2 is 0) { @@ -126,24 +158,38 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[] pszDefaultFolderPath, null, IID.IID_IShellItem, - (void**)pDefaultFolderShellItem.GetAddressOf()) - .ThrowOnFailure(); + (void**)pDefaultFolderShellItem.GetAddressOf()); + + // Handle shell item creation failure gracefully + if (hr.Failed) + { + App.Logger.LogWarning("Failed to create shell item for default folder '{0}'. HRESULT: 0x{1:X8}. Dialog will open without default folder.", Environment.GetFolderPath(defaultFolder), hr.Value); + // Continue without setting default folder rather than failing completely + } } // Folder picker if (pickFoldersOnly) pDialog.Get()->SetOptions(FILEOPENDIALOGOPTIONS.FOS_PICKFOLDERS); - // Set the default folder to open in the dialog - pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get()); - pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get()); + // Set the default folder to open in the dialog (only if creation succeeded) + if (pDefaultFolderShellItem.Get() is not null) + { + pDialog.Get()->SetFolder(pDefaultFolderShellItem.Get()); + pDialog.Get()->SetDefaultFolder(pDefaultFolderShellItem.Get()); + } // Show the dialog hr = pDialog.Get()->Show(new HWND(hWnd)); if (hr.Value == unchecked((int)0x800704C7)) // HRESULT_FROM_WIN32(ERROR_CANCELLED) return false; - hr.ThrowOnFailure(); + // Handle dialog show failure gracefully + if (hr.Failed) + { + App.Logger.LogError("Failed to show FileSaveDialog. HRESULT: 0x{0:X8}", hr.Value); + return false; + } // Get the file that user chose using ComPtr pResultShellItem = default; @@ -155,10 +201,14 @@ public unsafe bool Open_FileSaveDialog(nint hWnd, bool pickFoldersOnly, string[] return true; } + catch (COMException comEx) + { + App.Logger.LogError(comEx, "COM failure while opening FileSaveDialog. HRESULT: 0x{0:X8}", comEx.HResult); + return false; + } catch (Exception ex) { - App.Logger.LogError(ex, "Failed to open FileSaveDialog."); - + App.Logger.LogError(ex, "Unexpected error while opening FileSaveDialog."); return false; } }