Skip to content

Fix Issue 14721: TreeView.CustomDraw leaks one HFONT per visible item per paint when NodeFont is set, leading to GDI handle exhaustion and crash#14730

Open
SimonZhao888 wants to merge 3 commits into
dotnet:mainfrom
SimonZhao888:Fix_Issue_14721
Open

Fix Issue 14721: TreeView.CustomDraw leaks one HFONT per visible item per paint when NodeFont is set, leading to GDI handle exhaustion and crash#14730
SimonZhao888 wants to merge 3 commits into
dotnet:mainfrom
SimonZhao888:Fix_Issue_14721

Conversation

@SimonZhao888

@SimonZhao888 SimonZhao888 commented Jul 13, 2026

Copy link
Copy Markdown
Member

Fixes #14721

Root Cause

TreeView.CustomDraw calls GetItemRenderStyles during every ITEMPREPAINT event, and this method creates a new OwnerDrawPropertyBag. The original code utilized renderinfo.FontHandle, which triggered Font.ToHfont()—allocating a new HFONT—whenever the property was first accessed in a new bag. Because these short-lived objects could not be released immediately, GDI font handles accumulated rapidly during high-frequency repainting, eventually leading to handle exhaustion and a crash.

Proposed changes

  • The source for selecting the font into the Device Context has been changed from renderinfo.FontHandle to node._propBag.FontHandle, utilizing the reusable, long-lived cache available on the TreeNode. Null checks (for node._propBag and node._propBag.Font) are retained to ensure safety. This change preserves standard rendering semantics (using the same font source) while avoiding the repeated creation of an HFONT during every paint operation.
  • In OwnerDrawPropertyBag, change Font from an auto-property to one with a custom setter: when the font changes, explicitly dispose of the old _fontWrapper and set it to null, ensuring that the correct HFONT is recreated the next time FontHandle is accessed.

Customer Impact

  • Avoid exceptions (such as Win32Exception: The operation completed successfully.) and subsequent application crashes (0xC000041D) caused by reaching the 10,000 GDI handle limit.
  • Reduce or eliminate the rapid proliferation of GDI font handles during frequent TreeView repainting.
  • After switching TreeNode.NodeFont at runtime, the new font is correctly reflected, and the old HFONT is not used.

Regression?

  • No

Risk

  • Mini

Screenshots

Before

14721-Before.mp4

After

14721-After.mp4

Change the font of a TreeNode:

14721-After2.mp4

Test methodology

  • Manually

Test environment(s)

  • 11.0.100-preview.5.26302.115
Microsoft Reviewers: Open in CodeFlow

… per paint when NodeFont is set, leading to GDI handle exhaustion and crash
@SimonZhao888 SimonZhao888 requested a review from a team as a code owner July 13, 2026 06:58
@SimonZhao888 SimonZhao888 requested review from Copilot and removed request for a team July 13, 2026 06:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 GDI handle leak in TreeView.CustomDraw by avoiding per-paint HFONT creation when TreeNode.NodeFont is set, reducing the risk of GDI handle exhaustion and process crashes during frequent repaint scenarios.

Changes:

  • Switches the selected font handle in the custom draw path from a short-lived OwnerDrawPropertyBag instance to the node’s long-lived _propBag cache.
  • Adds guards/asserts around _propBag usage when selecting the font into the item DC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TreeView.CustomDraw leaks one HFONT per visible item per paint when NodeFont is set, leading to GDI handle exhaustion and crash

2 participants