Reputation: 1068
I found out that after FillRgn() Windows GDI API function, the GDI object used in this function is somehow "stuck" somewhere in the internal system maps and won't delete properly: calling DeleteObject() on the object returns successfully, but the number of GDI objects for the process does not decrement. Here is the code:
void gditest()
{
HBRUSH h = CreateSolidBrush(RGB(255, 237, 5));
HRGN rgn = CreateRectRgn(0, 100, 100, 0);
FillRgn(g_DC, rgn, h);
int before = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
SelectObject(g_DC, GetStockObject(WHITE_BRUSH));
int rs = DeleteObject( h );
if ( !rs )
throw;
int after = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
}
The code demonstrates that after deleting the HBRUSH handle variables 'before' and 'after' are equal; g_DC is the main window HDC.
How to delete the 'h' so that the number of GDI objects were decrementing?
Upvotes: 3
Views: 2048
Reputation: 47954
Either GDI is caching the brush and region resources, or it's a bug. The count does not go down after deleting the brush or the region. Tested on Windows 7. Here's my quick-and-dirty repro code:
#include <cassert>
#include <iostream>
#include <windows.h>
void PrintGdiCount() {
std::cout << ::GetGuiResources(::GetCurrentProcess(), GR_GDIOBJECTS)
<< std::endl;
}
int main() {
PrintGdiCount();
::GdiSetBatchLimit(1); // disable batching
HDC hdcScreen = ::GetDC(NULL);
PrintGdiCount();
HDC hdcMemory = ::CreateCompatibleDC(hdcScreen);
PrintGdiCount();
HBITMAP hbmpMemory = ::CreateCompatibleBitmap(hdcScreen, 100, 100);
PrintGdiCount();
HBITMAP hbmpOld = reinterpret_cast<HBITMAP>(::SelectObject(hdcMemory, hbmpMemory));
PrintGdiCount();
HBRUSH hbrush = ::CreateSolidBrush(RGB(255, 127, 32));
PrintGdiCount();
HRGN hrgn = ::CreateRectRgn(0, 0, 50, 50);
PrintGdiCount();
// ::FillRgn(hdcMemory, hrgn, hbrush); // doesn't affect GDI count
PrintGdiCount();
BOOL bDeletedBrush = ::DeleteObject(hbrush);
assert(bDeletedBrush);
PrintGdiCount(); // expected decrement, but it doesn't
::DeleteObject(hrgn);
PrintGdiCount(); // expected decrement, but it doesn't
::SelectObject(hdcMemory, hbmpOld);
::DeleteObject(hbmpMemory);
PrintGdiCount();
::DeleteDC(hdcMemory);
PrintGdiCount();
::ReleaseDC(NULL, hdcScreen);
PrintGdiCount(); // result is 2 higher than initial count
return 0;
}
Upvotes: 1
Reputation: 693
When calling SelectObject() for the first time, you have to remember the return value and select it again once you are done with the DC. Also, you have to delete all created GDI objects.
void gditest()
{
HBRUSH h = CreateSolidBrush(RGB(255, 237, 5));
HRGN rgn = CreateRectRgn(0, 100, 100, 0);
FillRgn(g_DC, rgn, h);
int before = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
HBRUSH oldBrush = SelectObject(g_DC, GetStockObject(WHITE_BRUSH));
SelectObject( g_DC, oldBrush );
int rs = DeleteObject( h );
if ( !rs )
throw;
DeleteObject( rgn );
int after = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
}
Note:
Objects retrieved by GetStockObject() can be deleted, but they don't have to.
Upvotes: 1