-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Enable retry mechanism is Fluent Crashes #11284
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
base: main
Are you sure you want to change the base?
Conversation
|
|
||
| public static int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset) | ||
| { | ||
| int retryCount = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no flag which we can add to enable/disable this functionality ? (VelocityKey, Containment ? )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it makes sense. We can use AppContextSwitch for containment. Will make the changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements a retry mechanism for the DwmExtendFrameIntoClientArea Win32 API call to address repetitive crashes in WPF's Fluent theme implementation. The change wraps the previously direct P/Invoke declaration with error handling that attempts the operation up to 2 times with a 100ms delay between attempts.
Key changes:
- Converted direct P/Invoke method to private
_DwmExtendFrameIntoClientAreaand added public wrapper with retry logic - Catches
COMExceptionfrom DWM API failures and returns error HRESULT instead of crashing - Added
System.Threadingnamespace import forThread.Sleepfunctionality
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // DWM composition may not be available or the operation failed | ||
| // Return the error code rather than crashing the application | ||
| retryCount--; | ||
| if(retryCount == 0) |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after 'if' keyword. Should be if (retryCount == 0) for consistency with C# formatting conventions.
| if(retryCount == 0) | |
| if (retryCount == 0) |
|
|
||
| public static int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset) | ||
| { | ||
| int retryCount = 2; |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The retry logic may be confusing. With retryCount = 2, the code makes at most 2 total attempts (1 initial + 1 retry), not 2 retries as the PR description suggests. If the intention is to retry twice after the initial failure (3 total attempts), retryCount should be initialized to 3. Consider clarifying the intended behavior or adding a comment explaining that retryCount represents total attempts.
| return ex.HResult; | ||
| } | ||
| System.Diagnostics.Trace.WriteLine($"DwmExtendFrameIntoClientArea: retrying after COMException (HResult={ex.HResult})"); | ||
| Thread.Sleep(100); |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using Thread.Sleep(100) blocks the calling thread. If this method is called from a UI thread (which is likely given it's dealing with window composition), it will freeze the UI for 100ms on retry. Consider using a smaller delay (e.g., 10-50ms) or document that callers should invoke this on a background thread if the blocking behavior is acceptable.
| Thread.Sleep(100); | |
| // WARNING: This will block the calling thread. If called from the UI thread, it may cause UI freezing. | |
| Thread.Sleep(20); // Reduced from 100ms to 20ms to minimize UI impact. |
|
|
||
| [DllImport("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", PreserveSig = true)] | ||
| private static extern HRESULT _DwmGetColorizationColor(out uint pcrColorization, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend); | ||
|
|
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] This public method lacks documentation. Consider adding XML documentation comments to explain:
- The retry behavior (number of attempts and delay)
- Return value semantics (HRESULT - 0 for success, error code on failure)
- When/why retries might be necessary (transient DWM composition issues)
Similar wrapper methods like DwmGetColorizationColor include explanatory comments about error handling.
| /// <summary> | |
| /// Extends the window frame into the client area for the specified window using Desktop Window Manager (DWM). | |
| /// </summary> | |
| /// <param name="hwnd">A handle to the window to which the frame will be extended.</param> | |
| /// <param name="pMarInset">A reference to a <see cref="MARGINS"/> structure that describes the margins to use when extending the frame.</param> | |
| /// <returns> | |
| /// Returns 0 (S_OK) if the operation succeeds; otherwise, returns an HRESULT error code. | |
| /// </returns> | |
| /// <remarks> | |
| /// This method wraps the native DwmExtendFrameIntoClientArea API and implements a retry mechanism to handle transient DWM composition issues. | |
| /// If a <see cref="System.Runtime.InteropServices.COMException"/> is thrown (e.g., if DWM composition is temporarily unavailable), | |
| /// the method will retry the operation once after a 100ms delay (for a total of 2 attempts). | |
| /// If both attempts fail, the HRESULT from the exception is returned. | |
| /// </remarks> |
| } | ||
| } | ||
|
|
||
| return 0; |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This return statement is unreachable. The while loop can only exit via return statements inside the loop (line 2522 or 2531), making this line dead code. Consider removing it or restructuring the logic to make the control flow clearer.
| return 0; |
| public static int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset) | ||
| { | ||
| int retryCount = 2; | ||
| while(retryCount > 0) |
Copilot
AI
Nov 25, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after 'while' keyword. Should be while (retryCount > 0) for consistency with C# formatting conventions.
| while(retryCount > 0) | |
| while (retryCount > 0) |
JanviMahajan14
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Description
The following changes aim to fix certain repetitive crashes due to win32 DWM API. The idea here is to re-try extending content into client area which might result in a crash for about 2 times and if that still results in an exception, we log the same.
cc:/ @himgoyalmicro
Customer Impact
Possibly lesser crashes in fluent and might help in fluent adoption
Regression
Yes
Testing
Local Build Pass
Sample Application Testing
Tested with a runtime application
Risk
Low, things are very much in parity with previous impl.
Microsoft Reviewers: Open in CodeFlow