From 3798a101a63abd5f67dd8ceb14aaaa627283905d Mon Sep 17 00:00:00 2001 From: Davide Giacometti Date: Wed, 7 Aug 2024 13:41:51 +0200 Subject: [PATCH] [PreviewPane] Fix form positioning issues (#34035) ## Summary of the Pull Request This PR aims to fix some positioning issues of the form used as preview handler. It fixes the following issues: 1. The floating window, detached from Explorer that sometimes appears: #33491 #27475 #24985 2. The **CoreWebView2 members cannot be accessed after the WebView2 control is disposed** crash: #27276 3. `PowerToys.*.PreviewHandler.exe` process leak ### Repro steps for issue 1 - Navigate through files in a folder invoking their preview handler - Minimize/Restore Explorer quickly (spam WIN+D usually works) - 2 weird issues happen: - Some `PowerToys.*.PreviewHandler.exe` processes are leaked - Some `PowerToys.*.PreviewHandler.exe` are started with a `NULL` `HWND` ![Screenshot 2024-07-27 **200207](https://github.com/user-attachments/assets/5cb6c857-ad93-422a-8c5b-47bd1c492dce) This happens because [IPreviewHandler::DoPreview](https://learn.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipreviewhandler-dopreview) is called multiple times and sometimes before calling [IPreviewHandler::SetWindow](https://learn.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipreviewhandler-setwindow). When the managed previewer try to set the parent of the form to the `NULL` `HWND`, the desktop window is used instead, resulting in the floating preview window being displayed. Reference: https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setparent#parameters https://github.com/microsoft/PowerToys/blob/5d77874382f55cdf5268b19ebb97ec07727ca78f/src/modules/previewpane/common/controls/FormHandlerControl.cs#L136 ### Repro steps for issue 2 - Preview a file - Restart `explorer.exe` process - Make sure `PowerToys.*.PreviewHandler.exe` is leaked and still running - Preview the same file again - Preview is displayed (another process is launched) - Minimize Explorer What happens here is that the form of the old process have an invalid `HWND` as parent but receive the `SetRect` for some reason. ## PR Checklist - [x] **Closes:** #33491 #27475 #24985 #27276 - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## Detailed Description of the Pull Request / Additional comments - Don't start preview pane process when `HWND` is `NULL` - Terminate the preview pane process when setting parent fails - Prevent leaking processes closing them when a new preview is requested - Fixed an issue where PDF and SVG previews weren't updated after restoring Explorer - Added some error handling in the `UpdateWindowBounds` method of the managed preview - Terminate the preview pane when the `SetRect` event is received but the parent `HWND` has become invalid ## Validation Steps Performed - Manually tested all preview panes also using multiple Explorer windows - Validated that when Explorer is minimized/restored the preview is updated - Tested the preview pane resize - Validated that no window, no taskbar icon and no errors appear on both repro steps --- .../GcodePreviewHandler/Program.cs | 15 ++++++++--- .../GcodePreviewHandler.cpp | 11 ++++++-- .../MarkdownPreviewHandler/Program.cs | 15 ++++++++--- .../MarkdownPreviewHandler.cpp | 11 ++++++-- .../MonacoPreviewHandler/Program.cs | 15 ++++++++--- .../MonacoPreviewHandler.cpp | 11 ++++++-- .../previewpane/PdfPreviewHandler/Program.cs | 15 ++++++++--- .../PdfPreviewHandler.cpp | 12 +++++++-- .../previewpane/QoiPreviewHandler/Program.cs | 15 ++++++++--- .../QoiPreviewHandler.cpp | 11 ++++++-- .../previewpane/SvgPreviewHandler/Program.cs | 15 ++++++++--- .../SvgPreviewHandler.cpp | 12 +++++++-- .../common/cominterop/NativeMethods.cs | 3 +++ .../common/controls/FormHandlerControl.cs | 25 +++++++++++++------ .../common/controls/IPreviewHandlerControl.cs | 8 +++--- 15 files changed, 154 insertions(+), 40 deletions(-) diff --git a/src/modules/previewpane/GcodePreviewHandler/Program.cs b/src/modules/previewpane/GcodePreviewHandler/Program.cs index 0b0696fd01..cddf09cee4 100644 --- a/src/modules/previewpane/GcodePreviewHandler/Program.cs +++ b/src/modules/previewpane/GcodePreviewHandler/Program.cs @@ -36,15 +36,24 @@ namespace Microsoft.PowerToys.PreviewHandler.Gcode Rectangle s = new Rectangle(left, top, right - left, bottom - top); _previewHandlerControl = new GcodePreviewHandlerControl(); - _previewHandlerControl.SetWindow(hwnd, s); + + if (!_previewHandlerControl.SetWindow(hwnd, s)) + { + return; + } + _previewHandlerControl.DoPreview(filePath); NativeEventWaiter.WaitForEventLoop( Constants.GcodePreviewResizeEvent(), () => { - Rectangle s = default(Rectangle); - _previewHandlerControl.SetRect(s); + Rectangle s = default; + if (!_previewHandlerControl.SetRect(s)) + { + // When the parent HWND became invalid, the application won't respond to Application.Exit(). + Environment.Exit(0); + } }, Dispatcher.CurrentDispatcher, _tokenSource.Token); diff --git a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp index 41a4fc202f..3ad3711dd0 100644 --- a/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp +++ b/src/modules/previewpane/GcodePreviewHandlerCpp/GcodePreviewHandler.cpp @@ -159,9 +159,9 @@ IFACEMETHODIMP GcodePreviewHandler::DoPreview() { try { - if (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0) + if (m_hwndParent == NULL || (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0)) { - // Postponing Start GcodePreviewHandler.exe, position not yet initialized. preview will be done after initialisation + // Postponing Start GcodePreviewHandler.exe, parent and position not yet initialized. Preview will be done after initialisation. return S_OK; } Logger::info(L"Starting GcodePreviewHandler.exe"); @@ -189,6 +189,13 @@ IFACEMETHODIMP GcodePreviewHandler::DoPreview() sei.lpParameters = cmdLine.c_str(); sei.nShow = SW_SHOWDEFAULT; ShellExecuteEx(&sei); + + // Prevent to leak processes: preview is called multiple times when minimizing and restoring Explorer window + if (m_process) + { + TerminateProcess(m_process, 0); + } + m_process = sei.hProcess; } catch (std::exception& e) diff --git a/src/modules/previewpane/MarkdownPreviewHandler/Program.cs b/src/modules/previewpane/MarkdownPreviewHandler/Program.cs index 8b6b66f974..3d5fe7c207 100644 --- a/src/modules/previewpane/MarkdownPreviewHandler/Program.cs +++ b/src/modules/previewpane/MarkdownPreviewHandler/Program.cs @@ -36,15 +36,24 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown Rectangle s = new Rectangle(left, top, right - left, bottom - top); _previewHandlerControl = new MarkdownPreviewHandlerControl(); - _previewHandlerControl.SetWindow(hwnd, s); + + if (!_previewHandlerControl.SetWindow(hwnd, s)) + { + return; + } + _previewHandlerControl.DoPreview(filePath); NativeEventWaiter.WaitForEventLoop( Constants.MarkdownPreviewResizeEvent(), () => { - Rectangle s = default(Rectangle); - _previewHandlerControl.SetRect(s); + Rectangle s = default; + if (!_previewHandlerControl.SetRect(s)) + { + // When the parent HWND became invalid, the application won't respond to Application.Exit(). + Environment.Exit(0); + } }, Dispatcher.CurrentDispatcher, _tokenSource.Token); diff --git a/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp index 66970506f3..2837880a42 100644 --- a/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp +++ b/src/modules/previewpane/MarkdownPreviewHandlerCpp/MarkdownPreviewHandler.cpp @@ -160,9 +160,9 @@ IFACEMETHODIMP MarkdownPreviewHandler::DoPreview() { try { - if (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0) + if (m_hwndParent == NULL || (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0)) { - // Postponing Start MarkdownPreviewHandler.exe, position not yet initialized. preview will be done after initialisation + // Postponing Start MarkdownPreviewHandler.exe, parent and position not yet initialized. Preview will be done after initialisation. return S_OK; } Logger::info(L"Starting MarkdownPreviewHandler.exe"); @@ -190,6 +190,13 @@ IFACEMETHODIMP MarkdownPreviewHandler::DoPreview() sei.lpParameters = cmdLine.c_str(); sei.nShow = SW_SHOWDEFAULT; ShellExecuteEx(&sei); + + // Prevent to leak processes: preview is called multiple times when minimizing and restoring Explorer window + if (m_process) + { + TerminateProcess(m_process, 0); + } + m_process = sei.hProcess; } catch (std::exception& e) diff --git a/src/modules/previewpane/MonacoPreviewHandler/Program.cs b/src/modules/previewpane/MonacoPreviewHandler/Program.cs index 7821d25658..fabb0ca710 100644 --- a/src/modules/previewpane/MonacoPreviewHandler/Program.cs +++ b/src/modules/previewpane/MonacoPreviewHandler/Program.cs @@ -39,15 +39,24 @@ namespace Microsoft.PowerToys.PreviewHandler.Monaco Rectangle s = new Rectangle(left, top, right - left, bottom - top); _previewHandlerControl = new MonacoPreviewHandlerControl(); - _previewHandlerControl.SetWindow(hwnd, s); + + if (!_previewHandlerControl.SetWindow(hwnd, s)) + { + return; + } + _previewHandlerControl.DoPreview(filePath); NativeEventWaiter.WaitForEventLoop( Constants.DevFilesPreviewResizeEvent(), () => { - Rectangle s = default(Rectangle); - _previewHandlerControl.SetRect(s); + Rectangle s = default; + if (!_previewHandlerControl.SetRect(s)) + { + // When the parent HWND became invalid, the application won't respond to Application.Exit(). + Environment.Exit(0); + } }, Dispatcher.CurrentDispatcher, _tokenSource.Token); diff --git a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp index 724e140574..004427de69 100644 --- a/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp +++ b/src/modules/previewpane/MonacoPreviewHandlerCpp/MonacoPreviewHandler.cpp @@ -159,9 +159,9 @@ IFACEMETHODIMP MonacoPreviewHandler::DoPreview() { try { - if (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0) + if (m_hwndParent == NULL || (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0)) { - // Postponing Start MonacoPreviewHandler.exe, position not yet initialized. preview will be done after initialisation + // Postponing Start MonacoPreviewHandler.exe, parent and position not yet initialized. Preview will be done after initialisation. return S_OK; } @@ -189,6 +189,13 @@ IFACEMETHODIMP MonacoPreviewHandler::DoPreview() sei.lpParameters = cmdLine.c_str(); sei.nShow = SW_SHOWDEFAULT; ShellExecuteEx(&sei); + + // Prevent to leak processes: preview is called multiple times when minimizing and restoring Explorer window + if (m_process) + { + TerminateProcess(m_process, 0); + } + m_process = sei.hProcess; } catch (std::exception& e) diff --git a/src/modules/previewpane/PdfPreviewHandler/Program.cs b/src/modules/previewpane/PdfPreviewHandler/Program.cs index d9427dc215..7c883b7989 100644 --- a/src/modules/previewpane/PdfPreviewHandler/Program.cs +++ b/src/modules/previewpane/PdfPreviewHandler/Program.cs @@ -35,15 +35,24 @@ namespace Microsoft.PowerToys.PreviewHandler.Pdf Rectangle s = new Rectangle(left, top, right - left, bottom - top); _previewHandlerControl = new PdfPreviewHandlerControl(); - _previewHandlerControl.SetWindow(hwnd, s); + + if (!_previewHandlerControl.SetWindow(hwnd, s)) + { + return; + } + _previewHandlerControl.DoPreview(filePath); NativeEventWaiter.WaitForEventLoop( Constants.PdfPreviewResizeEvent(), () => { - Rectangle s = default(Rectangle); - _previewHandlerControl.SetRect(s); + Rectangle s = default; + if (!_previewHandlerControl.SetRect(s)) + { + // When the parent HWND became invalid, the application won't respond to Application.Exit(). + Environment.Exit(0); + } }, Dispatcher.CurrentDispatcher, _tokenSource.Token); diff --git a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp index 7ad100bbc4..aadc5ce709 100644 --- a/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp +++ b/src/modules/previewpane/PdfPreviewHandlerCpp/PdfPreviewHandler.cpp @@ -147,6 +147,7 @@ IFACEMETHODIMP PdfPreviewHandler::SetRect(const RECT* prc) } } } + m_rcParent = *prc; hr = S_OK; } return hr; @@ -156,9 +157,9 @@ IFACEMETHODIMP PdfPreviewHandler::DoPreview() { try { - if (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0) + if (m_hwndParent == NULL || (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0)) { - // Postponing Start PdfPreviewHandler.exe, position not yet initialized. preview will be done after initialisation + // Postponing Start PdfPreviewHandler.exe, parent and position not yet initialized. Preview will be done after initialisation. return S_OK; } Logger::info(L"Starting PdfPreviewHandler.exe"); @@ -186,6 +187,13 @@ IFACEMETHODIMP PdfPreviewHandler::DoPreview() sei.lpParameters = cmdLine.c_str(); sei.nShow = SW_SHOWDEFAULT; ShellExecuteEx(&sei); + + // Prevent to leak processes: preview is called multiple times when minimizing and restoring Explorer window + if (m_process) + { + TerminateProcess(m_process, 0); + } + m_process = sei.hProcess; } catch (std::exception& e) diff --git a/src/modules/previewpane/QoiPreviewHandler/Program.cs b/src/modules/previewpane/QoiPreviewHandler/Program.cs index 5a9f5bfa2b..469d0c3b25 100644 --- a/src/modules/previewpane/QoiPreviewHandler/Program.cs +++ b/src/modules/previewpane/QoiPreviewHandler/Program.cs @@ -36,15 +36,24 @@ namespace Microsoft.PowerToys.PreviewHandler.Qoi Rectangle s = new Rectangle(left, top, right - left, bottom - top); _previewHandlerControl = new QoiPreviewHandlerControl(); - _previewHandlerControl.SetWindow(hwnd, s); + + if (!_previewHandlerControl.SetWindow(hwnd, s)) + { + return; + } + _previewHandlerControl.DoPreview(filePath); NativeEventWaiter.WaitForEventLoop( Constants.QoiPreviewResizeEvent(), () => { - Rectangle s = default(Rectangle); - _previewHandlerControl.SetRect(s); + Rectangle s = default; + if (!_previewHandlerControl.SetRect(s)) + { + // When the parent HWND became invalid, the application won't respond to Application.Exit(). + Environment.Exit(0); + } }, Dispatcher.CurrentDispatcher, _tokenSource.Token); diff --git a/src/modules/previewpane/QoiPreviewHandlerCpp/QoiPreviewHandler.cpp b/src/modules/previewpane/QoiPreviewHandlerCpp/QoiPreviewHandler.cpp index 9d1ce0a813..7cf8873bba 100644 --- a/src/modules/previewpane/QoiPreviewHandlerCpp/QoiPreviewHandler.cpp +++ b/src/modules/previewpane/QoiPreviewHandlerCpp/QoiPreviewHandler.cpp @@ -159,9 +159,9 @@ IFACEMETHODIMP QoiPreviewHandler::DoPreview() { try { - if (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0) + if (m_hwndParent == NULL || (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0)) { - // Postponing Start QoiPreviewHandler.exe, position not yet initialized. preview will be done after initialisation + // Postponing Start QoiPreviewHandler.exe, parent and position not yet initialized. Preview will be done after initialisation. return S_OK; } Logger::info(L"Starting QoiPreviewHandler.exe"); @@ -189,6 +189,13 @@ IFACEMETHODIMP QoiPreviewHandler::DoPreview() sei.lpParameters = cmdLine.c_str(); sei.nShow = SW_SHOWDEFAULT; ShellExecuteEx(&sei); + + // Prevent to leak processes: preview is called multiple times when minimizing and restoring Explorer window + if (m_process) + { + TerminateProcess(m_process, 0); + } + m_process = sei.hProcess; } catch (std::exception& e) diff --git a/src/modules/previewpane/SvgPreviewHandler/Program.cs b/src/modules/previewpane/SvgPreviewHandler/Program.cs index 4b506ded1a..e46e9f784c 100644 --- a/src/modules/previewpane/SvgPreviewHandler/Program.cs +++ b/src/modules/previewpane/SvgPreviewHandler/Program.cs @@ -36,15 +36,24 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg Rectangle s = new Rectangle(left, top, right - left, bottom - top); _previewHandlerControl = new SvgPreviewControl(); - _previewHandlerControl.SetWindow(hwnd, s); + + if (!_previewHandlerControl.SetWindow(hwnd, s)) + { + return; + } + _previewHandlerControl.DoPreview(filePath); NativeEventWaiter.WaitForEventLoop( Constants.SvgPreviewResizeEvent(), () => { - Rectangle s = default(Rectangle); - _previewHandlerControl.SetRect(s); + Rectangle s = default; + if (!_previewHandlerControl.SetRect(s)) + { + // When the parent HWND became invalid, the application won't respond to Application.Exit(). + Environment.Exit(0); + } }, Dispatcher.CurrentDispatcher, _tokenSource.Token); diff --git a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp index 174163f77a..e0c257db49 100644 --- a/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp +++ b/src/modules/previewpane/SvgPreviewHandlerCpp/SvgPreviewHandler.cpp @@ -149,6 +149,7 @@ IFACEMETHODIMP SvgPreviewHandler::SetRect(const RECT* prc) } } } + m_rcParent = *prc; hr = S_OK; } return hr; @@ -158,9 +159,9 @@ IFACEMETHODIMP SvgPreviewHandler::DoPreview() { try { - if (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0) + if (m_hwndParent == NULL || (m_rcParent.left == 0 && m_rcParent.top == 0 && m_rcParent.right == 0 && m_rcParent.bottom == 0)) { - // Postponing Start SvgPreviewHandler.exe, position not yet initialized. preview will be done after initialisation + // Postponing Start SvgPreviewHandler.exe, parent and position not yet initialized. Preview will be done after initialisation. return S_OK; } Logger::info(L"Starting SvgPreviewHandler.exe"); @@ -188,6 +189,13 @@ IFACEMETHODIMP SvgPreviewHandler::DoPreview() sei.lpParameters = cmdLine.c_str(); sei.nShow = SW_SHOWDEFAULT; ShellExecuteEx(&sei); + + // Prevent to leak processes: preview is called multiple times when minimizing and restoring Explorer window + if (m_process) + { + TerminateProcess(m_process, 0); + } + m_process = sei.hProcess; } catch (std::exception& e) diff --git a/src/modules/previewpane/common/cominterop/NativeMethods.cs b/src/modules/previewpane/common/cominterop/NativeMethods.cs index 611136b1a3..58979d0ff8 100644 --- a/src/modules/previewpane/common/cominterop/NativeMethods.cs +++ b/src/modules/previewpane/common/cominterop/NativeMethods.cs @@ -37,5 +37,8 @@ namespace PreviewHandlerCommon.ComInterop [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetClientRect(IntPtr hWnd, ref Common.ComInterlop.RECT rect); + + [DllImport("user32.dll")] + public static extern bool IsWindow(IntPtr hWnd); } } diff --git a/src/modules/previewpane/common/controls/FormHandlerControl.cs b/src/modules/previewpane/common/controls/FormHandlerControl.cs index ef798ed424..dd3cd9f897 100644 --- a/src/modules/previewpane/common/controls/FormHandlerControl.cs +++ b/src/modules/previewpane/common/controls/FormHandlerControl.cs @@ -73,9 +73,9 @@ namespace Common } /// - public void SetRect(Rectangle windowBounds) + public bool SetRect(Rectangle windowBounds) { - this.UpdateWindowBounds(parentHwnd, windowBounds); + return this.UpdateWindowBounds(parentHwnd, windowBounds); } /// @@ -85,10 +85,10 @@ namespace Common } /// - public void SetWindow(IntPtr hwnd, Rectangle rect) + public bool SetWindow(IntPtr hwnd, Rectangle rect) { this.parentHwnd = hwnd; - this.UpdateWindowBounds(hwnd, rect); + return this.UpdateWindowBounds(hwnd, rect); } /// @@ -118,12 +118,18 @@ namespace Common /// /// Update the Form Control window with the passed rectangle. /// - public void UpdateWindowBounds(IntPtr hwnd, Rectangle newBounds) + public bool UpdateWindowBounds(IntPtr hwnd, Rectangle newBounds) { + if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) + { + // If the HWND is IntPtr.Zero the desktop window will be used as parent. + return false; + } + if (this.Disposing || this.IsDisposed) { // For unclear reasons, this can be called when handling an error and the form has already been disposed. - return; + return false; } // We must set the WS_CHILD style to change the form to a control within the Explorer preview pane @@ -133,7 +139,10 @@ namespace Common _ = NativeMethods.SetWindowLong(Handle, gwlStyle, windowStyle | wsChild); } - NativeMethods.SetParent(Handle, hwnd); + if (NativeMethods.SetParent(Handle, hwnd) == IntPtr.Zero) + { + return false; + } if (newBounds.IsEmpty) { @@ -146,6 +155,8 @@ namespace Common { Bounds = newBounds; } + + return true; } } } diff --git a/src/modules/previewpane/common/controls/IPreviewHandlerControl.cs b/src/modules/previewpane/common/controls/IPreviewHandlerControl.cs index a5e074b8db..c0b7bc291f 100644 --- a/src/modules/previewpane/common/controls/IPreviewHandlerControl.cs +++ b/src/modules/previewpane/common/controls/IPreviewHandlerControl.cs @@ -58,14 +58,16 @@ namespace Common /// Directs the control to change the area within the parent hwnd that it draws into. /// /// Instance of Rectangle defining the area. - void SetRect(Rectangle windowBounds); + /// if the operation was successful; otherwise, . + bool SetRect(Rectangle windowBounds); /// - /// Sets the parent window of the previewer window, as well as the area within the parent to be used for the previewer window.. + /// Sets the parent window of the previewer window, as well as the area within the parent to be used for the previewer window. /// /// Pointer to the parent window handle. /// Instance of Rectangle defining the area. - void SetWindow(IntPtr hwnd, Rectangle rect); + /// if the operation was successful; otherwise, . + bool SetWindow(IntPtr hwnd, Rectangle rect); /// /// Called by Preview Handler to start the preview.