Skip to content

Commit

Permalink
Stabilize ImageList_FinalizerReleasesNativeHandle_ReturnsExpected
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Dec 29, 2023
1 parent 58ffd1a commit f8da870
Showing 1 changed file with 37 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32.System.Threading;
using Xunit.Abstractions;
Expand All @@ -20,48 +21,70 @@ public ImageListTests(ITestOutputHelper testOutputHelper)
{
}

[ActiveIssue("https://github.com/dotnet/winforms/issues/6635")]
[WinFormsFact(Skip = "Flaky tests, see: https://github.com/dotnet/winforms/issues/6635")]
[WinFormsFact]
public void ImageList_FinalizerReleasesNativeHandle_ReturnsExpected()
{
// Call GetGdiHandles at the start of the test to attempt to clear out any leftovers from previous tests
uint referenceGdiHandleCount = GetGdiHandles();
TestOutputHelper.WriteLine($"Reference GDI handle count at start of test: {referenceGdiHandleCount}");

// Warm up to create any GDI handles that are necessary, e.g. fonts, brushes, etc.
using (Form form = CreateForm())
{
form.Show();
}
ShowForm();

uint startGdiHandleCount = GetGdiHandles();
TestOutputHelper.WriteLine($"GDI handles before: {startGdiHandleCount}");

// Now test for real
using (Form form = CreateForm())
{
form.Show();
}
ShowForm();

uint endGdiHandleCount = GetGdiHandles();
TestOutputHelper.WriteLine($"GDI handles after: {endGdiHandleCount}");

Assert.Equal(startGdiHandleCount, endGdiHandleCount);

[MethodImpl(MethodImplOptions.NoInlining)]
static uint GetGdiHandles()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect(0);
uint result = GetGdiHandlesOnce();
while (true)
{
uint updatedResult = GetGdiHandlesOnce();
if (updatedResult == result)
{
// When two invocations return the same value, it's assumed to have stabilized
return result;
}

result = updatedResult;
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
static uint GetGdiHandlesOnce()
{
GC.GetTotalMemory(true);

uint result = PInvoke.GetGuiResources((HANDLE)Process.GetCurrentProcess().Handle,
GET_GUI_RESOURCES_FLAGS.GR_GDIOBJECTS);
if (result == 0)
{
int lastWin32Error = Marshal.GetLastWin32Error();
throw new Win32Exception(lastWin32Error, "Failed to retrieves the count of GDI handles");
if (lastWin32Error != 0)
throw new Win32Exception(lastWin32Error, "Failed to retrieves the count of GDI handles");
}

return result;
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void ShowForm()
{
using Form form = CreateForm();
form.Show();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private Form CreateForm()
{
ListView listView1 = new()
Expand Down

0 comments on commit f8da870

Please sign in to comment.