Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/3.0] Prevent NULL HWND's from being parented under SystemResources listener windows #2102

Conversation

vatsan-madhavan
Copy link
Member

Addresses #2089
.NET 5 PR: #2100
.NET Core 3.1 PR: #2101

Description (Summary)

When HwndHost hosted HWND's need to be "parked" while the HwndHost is not being actively shown, WPF will reparent such HWND's under temporary message-only windows maintained inside the SystemResources class.

There is a bug that causes null HWND's to be parented under such message-only windows. When this happens in High-DPI applications that use mixed-mode DPI capabilities introduced by WPF in .NET 4.8 (parent and child windows with different DPI_AWARENESS_CONTEXT values), a crash ensues.

Customer Impact

This is a fix for a crash affecting several applications including Visual Studio, and Azure Information Protection Add-in for Office

This was fixed recently in .NET 4.8, and is being forwarded ported to .NET Core for consistency.

Regresssion

Not a regression in .NET Core, but this was a regression introduced by .NET 4.8.

Risk

The fix is small and well understood, and has been tested well. The .NET Framework version of this fix has been validated by Visual Studio (the codebases are identical in this area and .NET Framework testing is a reliable proxy for this change in .NET Core).

Details

When an HwndHost receives SourceChanged event, it goes through BuildOrReparentWindow. When the hosted window is invisible, it is usually reparented under a temporary windows maintained by WPF in the SystemResources class, until later on the window can be rebuilt and parented back to a valid parent.

There is a latent bug in this logic where in NULL HWND's are attempted to be parented to SystemResources managed temporary windows. This bug goes back quite a while (.NET 4.5 likely). WPF seems to ignore the return value from kernel32!SetParent and not deal with this failure. This has not been a crashing failure until now.

Starting .NET 4.8, there have been some changes to this codepath that has resulted in the current bug becoming a crash. In addition to calling kernel32!SetParent on a NULL HWND, WPF attempts to obtain a DPI-specific parking-window. This process of querying a DPI-specific parking window fails because WPF is unable to use the DPI_AWARENESS_CONTEXT value returned by the system for (HWND)nullptr.

The only necessary part of this fix is in HwndHost: WPF should not attempt to reparent the hosted window under a parking-window if the hosted window is (HWND)nullptr. This only requires a simple check : else if (_hwnd.Handle != IntPtr.Zero)). All other changes in SystemResources and HwndHost are defensive improvements.

SystemResources.EnsureResourceChangeListener(HwndDpiInfo) can attempt to create a parking-window corresponding to DPI_AWARENESS_CONTEXT_VALUE that is invalid/meaningless. This should not be allowed. A few additional checks are added to ensure this. Further, GetDpiAwarenessCompatibleNotificationWindow is augmented to be more defensive.

Also, variant of EnsureResourceChangeListener is dead code - it is being removed.

If for some unknown reason SystemResources.GetDpiAwarenessCompatibleNotificationWindow fails and returns null to HwndHost.BuildOrReparentWindow, WPF will fail to reparent the hosted window, and it will be 'lost'. This seems very unlikely - I have added a Trace to ensure that we can debug this situation if it does occur.

…uildOrReparentWindow`. When the hosted window is invisible, it is usually reparented under a temporary windows maintained by WPF in the `SystemResources `class, until later on the window can be rebuilt and parented back to a valid parent.

There is a latent bug in this logic where in `NULL ` `HWND's `are attempted to be parented to `SystemResources `managed temporary windows. This bug goes back quite a while (.NET 4.5 likely). WPF seems to ignore the return value from `kernel32!SetParent` and not deal with this failure. This has not been a crashing failure until now.

Starting .NET 4.8, there have been some changes to this codepath that has resulted in the current bug becoming a crash. In addition to calling `kernel32!SetParent` on a `NULL` `HWND`, WPF attempts to obtain a DPI-specific parking-window. This process of querying a DPI-specific parking window fails because WPF is unable to use the `DPI_AWARENESS_CONTEXT` value returned by the system for `(HWND)nullptr`.

The only necessary part of this fix is in `HwndHost`: WPF should not attempt to reparent the hosted window under a parking-window if the hosted window is `(HWND)nullptr`. This only requires a simple check : `else if (_hwnd.Handle != IntPtr.Zero)`). All other changes in `SystemResources` and `HwndHost` are defensive improvements.

`SystemResources.EnsureResourceChangeListener(HwndDpiInfo)` can attempt to create a parking-window corresponding to `DPI_AWARENESS_CONTEXT_VALUE` that is invalid/meaningless. This should not be allowed. A few additional checks are added to ensure this. Further, `GetDpiAwarenessCompatibleNotificationWindow` is augmented to be more defensive.

Also, variant of `EnsureResourceChangeListener`  is dead code - it is being removed.

If for some unknown reason `SystemResources.GetDpiAwarenessCompatibleNotificationWindow`  fails and returns `null` to `HwndHost.BuildOrReparentWindow`, WPF will fail to reparent the hosted window, and it will be 'lost'. This seems very unlikely - I have added a Trace to ensure that we can debug this situation if it does occur.
@ghost ghost requested a review from rladuca October 23, 2019 22:55
@ghost ghost added the PR metadata: Label to tag PRs, to facilitate with triage label Oct 23, 2019
@ghost ghost requested a review from SamBent October 23, 2019 22:55
@vatsan-madhavan vatsan-madhavan added Bug Product bug (most likely) issue-type-netfx-port Ports from .NET Framework labels Oct 23, 2019
@vatsan-madhavan vatsan-madhavan added this to the 3.0 Servicing milestone Oct 23, 2019
@vatsan-madhavan vatsan-madhavan self-assigned this Oct 25, 2019
@vatsan-madhavan vatsan-madhavan added Servicing-consider * NO MERGE * metadata: The PR is not ready for merge yet (see discussion for detailed reasons) labels Oct 25, 2019
@vatsan-madhavan
Copy link
Member Author

We are not forward porting .NET Framework fixes to release/3.0 - this will go into release/3.1 only.

@vatsan-madhavan vatsan-madhavan deleted the systemresources-hwnd-fixup-rel30 branch October 29, 2019 18:44
@ghost ghost locked as resolved and limited conversation to collaborators Apr 14, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug Product bug (most likely) issue-type-netfx-port Ports from .NET Framework * NO MERGE * metadata: The PR is not ready for merge yet (see discussion for detailed reasons) PR metadata: Label to tag PRs, to facilitate with triage Servicing-rejected
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants