Skip to content

Conversation

@LeafShi1
Copy link
Member

@LeafShi1 LeafShi1 commented Dec 9, 2025

Fixes #14122

Root Cause

The exception: An object could not be created, possibly due to a lack of memory, but most likely due to invalid input
was triggered because of how OnDrawItem handled icon creation in a high-frequency drawing path:

Repeated GDI object creation in hot path
Each call to OnDrawItem executed:

  • Icon.FromHandle(cursor.Handle)
  • Clone()
  • ScaleSmallIconToDpi(...)

This pattern allocates multiple unmanaged GDI resources per draw cycle. Under heavy redraw (scrolling, hover, DPI changes), these allocations accumulate quickly, exhausting GDI handles.

Proposed changes

  • Introduced a caching mechanism for scaled icon width based on (Cursor, DPI) to minimize redundant object creation.
  • Ensured ScaleSmallIconToDpi is still called as required, but only during cache population rather than every draw.
  • Added proper disposal of temporary Icon objects during cache initialization.
  • Cleared the cache in the End method to release resources when the control lifecycle ends.

Customer Impact

  • Eliminates random crashes caused by GDI handle exhaustion in owner-drawn controls.

Regression?

  • Yes

Risk

  • Minimal

Screenshots

Before

When using a PropertyGrid to edit properties of type Cursor, resizing the Cursor UITypeEditor drop-down window causes the application to stop responding or crash.

ResizeCursorEdiorIssue.mp4

After

AfterChanges.mp4

Test methodology

  • Manual testing

Test environment(s)

  • .net 10.0.0-rc.3.25603.106
Microsoft Reviewers: Open in CodeFlow

@codecov
Copy link

codecov bot commented Dec 9, 2025

Codecov Report

❌ Patch coverage is 13.33333% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.15542%. Comparing base (5d64bba) to head (2c380b6).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                 @@
##                main      #14123         +/-   ##
===================================================
+ Coverage   76.01271%   77.15542%   +1.14271%     
===================================================
  Files           3279        3279                 
  Lines         645325      645339         +14     
  Branches       47720       47721          +1     
===================================================
+ Hits          490529      497914       +7385     
+ Misses        145491      143737       -1754     
+ Partials        9305        3688       -5617     
Flag Coverage Δ
Debug 77.15542% <13.33333%> (+1.14271%) ⬆️
integration 18.99480% <0.00000%> (?)
production 52.02161% <13.33333%> (+2.56216%) ⬆️
test 97.40749% <ø> (ø)
unit 49.46226% <13.33333%> (+0.00281%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a 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 addresses a critical GDI resource exhaustion issue that causes crashes in owner-drawn controls during high-frequency drawing operations. The fix introduces intelligent caching of scaled icon widths to prevent repeated GDI object creation in hot code paths.

Key Changes:

  • Implemented a dictionary-based cache using (Cursor, DPI) tuples to store computed icon widths
  • Refactored OnDrawItem to use the cached values instead of repeatedly creating Icon objects
  • Added proper cache cleanup in the End() method to prevent memory leaks

Copy link
Member

@ricardobossan ricardobossan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Application crashes when resizing the Cursor editor in PropertyGrid

3 participants