-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix 13963: Ensure ScaleSmallIconToDpi Always Returns a New Icon to Prevent Resource Mismanagement #13971
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
Conversation
…event Resource Mismanagement
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 fixes a critical resource management bug where Form.UpdateWindowIcon
could inadvertently dispose of externally-owned icon instances. The fix ensures that ScaleSmallIconToDpi
always returns a new Icon instance, preventing the form from disposing icons that are still referenced by the caller.
Key Changes:
- Modified
ScaleHelper.ScaleSmallIconToDpi
to always create and return a new Icon instance instead of conditionally returning the original icon when dimensions match
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #13971 +/- ##
===================================================
+ Coverage 77.11724% 77.18829% +0.07104%
===================================================
Files 3271 3276 +5
Lines 644354 645116 +762
Branches 47658 47704 +46
===================================================
+ Hits 496908 497954 +1046
+ Misses 143766 143473 -293
- Partials 3680 3689 +9
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
I think that in particular case this is a right approach - always to create a new icon. But as I can see
So if we go this approach we need carefully examine all 3 other places and check - did we break anything? May be is safer (and a bit effectively) to modify
_smallIcon if new icon not created):
if (icon is not null)
{
Icon? newSmallIcon;
try
{
newSmallIcon = ScaleHelper.ScaleSmallIconToDpi(icon, dpi);
}
catch
{
newSmallIcon = _smallIcon;
}
if (newSmallIcon is not null)
{
PInvokeCore.SendMessage(this, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_SMALL, (LPARAM)newSmallIcon.Handle);
if (_smallIcon is not null && newSmallIcon != _smallIcon) // We will use a new icon - we need to dispose the old one.
{
_smallIcon.Dispose();
_smallIcon = null;
}
if (newSmallIcon != icon) // We don't need to save this icon unless we create a new instance.
_smallIcon = newSmallIcon;
}
PInvokeCore.SendMessage(this, PInvokeCore.WM_SETICON, (WPARAM)PInvoke.ICON_BIG, (LPARAM)icon.Handle);
} Also may be it will be useful to check other 3 |
You are right, however, as a helper method,
But this is indeed a breaking change, @JeremyKuhne @KlausLoeffelmann what do you think? |
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.
We cannot change this API to fix this regression. It has to be a targeted fix.
int height = PInvoke.GetCurrentSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSMICON, (uint)dpi); | ||
|
||
return (icon.Width == width && icon.Height == height) ? icon : new(icon, width, height); | ||
return new Icon(icon, width, height); |
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.
There are limited GDI handles available, making this sort of change is risky.
Fixes #13963
Root Cause
The issue was introduced in PR https://github.com/dotnet/winforms/pull/13787/files, which changed the
Form.UpdateWindowIcon
implementation from_smallIcon = new Icon(icon, SystemInformation.SmallIconSize);
to_smallIcon = ScaleHelper.ScaleSmallIconToDpi(icon, dpi);
The problem arises because
ScaleSmallIconToDpi
returns the original icon instance when its size already matches the target DPI. This caused_smallIcon
and the external icon to reference the same object. WhenUpdateWindowIcon
later disposed_smallIcon
, it unintentionally disposed the original icon as well, leading toObjectDisposedException
when the original icon was reused.Proposed changes
ScaleSmallIconToDpi
to always return a new Icon instance, even when the original icon already matches the target DPI size.Customer Impact
ObjectDisposedException
after closing a form, because the original icon gets disposed. This fix ensures the original icon remains valid and reusable, preventing these exceptions and improving reliability.Regression?
Risk
Screenshots
Before
With the demo code,
Click button1 and then click button2, exception dialog pops.
After
Click button1 and then click button2, the _ico.Handle displays normally.
Test methodology
Test environment(s)
Microsoft Reviewers: Open in CodeFlow