I've a very simple MFC dialog, with a single CComboBoxEx
control.
.rc
IDD_MFCAPPLICATION1_DIALOG DIALOGEX 0, 0, 160, 200
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "MFCApplication1"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
CONTROL "", IDC_COMBO1, "ComboBoxEx32", CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP, 10, 20, 140, 250
END
c++ source code
class CMFCApplication1Dlg : public CDialogEx
{
public:
CMFCApplication1Dlg(CWnd* pParent = NULL);
virtual void DoDataExchange( CDataExchange* pDX );
CComboBoxEx m_ctrlComboEx1;
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
};
CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent)
: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{}
void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_COMBO1, m_ctrlComboEx1);
}
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
END_MESSAGE_MAP()
BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
for (int i = 0; i<24; i++) // add useless junk text strings
{
COMBOBOXEXITEM cbei; memset(&cbei, 0, sizeof(cbei));
cbei.mask = CBEIF_TEXT;
cbei.iItem = i;
cbei.pszText = L"useless junk text string 4 handle leaks";
cbei.iImage = 0;
cbei.iSelectedImage = 0;
m_ctrlComboEx1.InsertItem(&cbei);
}
return TRUE;
}
When scrolling the items of the list box, the GDI-resources of the application rapidly increase and never get released.
See the image, which shows the effect and the increasing number of GDI-Objects in the task manager:
It seems this is related to the blue "highlighting" of the text items.
Windows-Specification
Edition Windows 10 Home
Version 1809
Installed on 19.12.2018
Operating System Build 17763.253
Scree scale 100%
Build
The issue accurse in both x64 Debug an Release configuration, so it seems not to be related to debug or optimization settings.
Is this a bug in my tiny application or is this a (possibly know) windows system bug?
If this is a windows bug, then is there a workaround?
GitHub repository with the full project: MFC-CComboBoxEx-Resource-Issue
Note:
GDI Resource leaks still not fixed with the following Windows 10 Preview Version:
Windows 10 19H1 Insider Preview Build 18317
Build Number 10.0.18317.1000
The CComboBoxEx control consists of a parent window, which encapsulates a CComboBox. The CComboBox object pointed to by the return value is a temporary object and is destroyed during the next idle processing time.
A pointer to a CEdit object. A CComboBoxEx control uses an edit box when it is created with the CBS_DROPDOWN style. The CEdit object pointed to by the return value is a temporary object and is destroyed during the next idle processing time.
A good solution for detecting GDI leaks is to use dedicated tools such as the Purify or BoundsChecker tools I mentioned earlier. The main drawback of these tools is the same as the final MFC dump for memory leaksâ€"you don't know about the leaks until the application ends.
SUMMARYLeaks are possible, even in robust Windows-based applications. As bugs go, leaks are some of the most difficult to find, especially when they occur in graphics device interface (GDI) objects and menus.
this is really bug of win 1809 version. when ComboboxEx is dropdown called
comctl32!ListBox_FillDrawItem
and then comctl32!ComboEx_OnDrawItem
. in windows 1709 (no handle leaks) i view the next:
but on windows 1809 - next:
here exist CreateSolidBrush
call, for which no DeleteObject
call.
also for test we can do next:
CBN_DROPDOWN
and
CBN_CLOSEUP
i use next code:
typedef struct
{
PVOID pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
PVOID pUserAddress;
} GDICELL;
struct DemoDlg
{
struct GH {
USHORT wType;
bool bPresent;
GH() : bPresent(true) {}
};
GDICELL* m_GdiSharedHandleTable;
SIZE_T m_nMaxHandleCount;
std::map<PVOID, GH> m_hm;
BOOL InitGDICheck()
{
_PEB* peb = RtlGetCurrentPeb();
GDICELL* GdiSharedHandleTable = (GDICELL*)peb->GdiSharedHandleTable;
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(GdiSharedHandleTable, &mbi, sizeof(mbi)))
{
m_nMaxHandleCount = mbi.RegionSize / sizeof(GDICELL);
m_GdiSharedHandleTable = GdiSharedHandleTable;
return TRUE;
}
return FALSE;
}
SIZE_T CheckGdiLeaks()
{
GDICELL* GdiSharedHandleTable = m_GdiSharedHandleTable;
SIZE_T nHandleCount = m_nMaxHandleCount, n = 0;
USHORT wProcessId = (USHORT)GetCurrentProcessId();
do
{
if (GdiSharedHandleTable->wProcessId == wProcessId)
{
n++;
GH& p = m_hm[GdiSharedHandleTable->pKernelAddress];
if (p.bPresent)
{
p.wType = GdiSharedHandleTable->wType;
DbgPrint("++%p>%04x\n", GdiSharedHandleTable->pKernelAddress, p.wType);
}
p.bPresent = true;
}
} while (GdiSharedHandleTable++, --nHandleCount);
auto end = m_hm.end(), it = m_hm.begin();
if (it != end)
{
do
{
GH& p = it->second;
if (p.bPresent)
{
p.bPresent = false;
it++;
}
else
{
DbgPrint("--%p>%04x\n", it->first, p.wType);
it = m_hm.erase(it);
}
} while (it != end);
}
return n;
}
static INT_PTR CALLBACK _DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_INITDIALOG)
{
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
}
if (DemoDlg* p = reinterpret_cast<DemoDlg*>(GetWindowLongPtrW(hwndDlg, DWLP_USER)))
{
return p->DialogProc(hwndDlg, uMsg, wParam, lParam);
}
return 0;
}
INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM /*lParam*/)
{
switch (uMsg)
{
case WM_INITDIALOG:
if (InitGDICheck())
{
COMBOBOXEXITEM cbei = { CBEIF_TEXT };
cbei.pszText = L"any text";
SendMessageW(GetDlgItem(hwndDlg, IDC_COMBOBOXEX1), CBEM_INSERTITEM, 0, (LPARAM)&cbei);
}
else
{
EndDialog(hwndDlg, 0);
}
break;
case WM_COMMAND:
switch (wParam)
{
case MAKEWPARAM(IDC_COMBOBOXEX1, CBN_DROPDOWN ):
DbgPrint("--- DROPDOWN [%x] --- \n", CheckGdiLeaks());
break;
case MAKEWPARAM(IDC_COMBOBOXEX1, CBN_CLOSEUP):
DbgPrint("--- CLOSEUP [%x] --- \n", CheckGdiLeaks());
break;
case MAKEWPARAM(IDCANCEL, BN_CLICKED):
EndDialog(hwndDlg, 1);
break;
}
break;
}
return 0;
}
};
{
DemoDlg dlg;
DialogBoxParamW((HINSTANCE)&__ImageBase,
MAKEINTRESOURCE(IDD_DIALOG1), HWND_DESKTOP, DemoDlg::_DialogProc, (LPARAM)&dlg);
}
with win 1709 i view next log:
++FFFFFFFFFF3C0DC0>0004
++FFFFFFFFFF81171B>0004
++FFFFFFFFFF06171F>0004
++FFFFFFFFFFA61737>0005
++FFFFFFFFFF8517D9>0001
--FFFFFFFFFF02171F>0004
--FFFFFFFFFF3A0DC0>0004
--FFFFFFFFFF80171B>0004
--FFFFFFFFFF8417D9>0005
--FFFFFFFFFFA51737>0001
--- DROPDOWN [a] ---
++FFFFFFFFFF470DC0>0004
++FFFFFFFFFF12171F>0004
++FFFFFFFFFF8917D9>0001
--FFFFFFFFFF06171F>0004
--FFFFFFFFFF3C0DC0>0004
--FFFFFFFFFF8517D9>0001
--- CLOSEUP [a] ---
++FFFFFFFFFF490DC0>0004
++FFFFFFFFFF85171B>0004
++FFFFFFFFFF13171F>0004
++FFFFFFFFFFA71737>0001
++FFFFFFFFFF8A17D9>0005
--FFFFFFFFFF12171F>0004
--FFFFFFFFFF470DC0>0004
--FFFFFFFFFF81171B>0004
--FFFFFFFFFF8917D9>0001
--FFFFFFFFFFA61737>0005
--- DROPDOWN [a] ---
++FFFFFFFFFF540DC0>0004
++FFFFFFFFFF91171B>0004
++FFFFFFFFFFAB1737>0001
--FFFFFFFFFF490DC0>0004
--FFFFFFFFFF85171B>0004
--FFFFFFFFFFA71737>0001
--- CLOSEUP [a] ---
count of gdi objects stay constant (0xa). some objects created and then destroyed.
but on latest 1809 another log:
++FFFFFFFFFF141043>0005
++FFFFFFFFFF1015B8>0004
++FFFFFFFFFF6B198C>0004
++FFFFFFFFFF3319B6>0001
++FFFFFFFFFFFB1A5E>0005
++FFFFFFFFFF6A1AC4>0004
++FFFFFFFFFF8C1B87>0001
++FFFFFFFFFF0F1C31>0004
--FFFFFFFFFF0515B8>0004
--FFFFFFFFFF060ED2>0001
--FFFFFFFFFF1010FF>0005
--FFFFFFFFFF3E198C>0004
--FFFFFFFFFF5A1AC4>0004
--FFFFFFFFFFD812DD>0001
--FFFFFFFFFFE11C31>0004
--FFFFFFFFFFFA0CFB>0005
--- DROPDOWN [10] ---
++FFFFFFFFFFCB08DF>0010
++FFFFFFFFFF1715B8>0004
++FFFFFFFFFF7E198C>0004
++FFFFFFFFFF3519B6>0001
++FFFFFFFFFF8F1B87>0001
++FFFFFFFFFF231C31>0004
--FFFFFFFFFF0F1C31>0004
--FFFFFFFFFF1015B8>0004
--FFFFFFFFFF3319B6>0001
--FFFFFFFFFF6B198C>0004
--FFFFFFFFFF8C1B87>0001
--- CLOSEUP [11] ---
++FFFFFFFFFF2615B8>0004
++FFFFFFFFFF87198C>0004
++FFFFFFFFFF3619B6>0001
++FFFFFFFFFF901B87>0001
++FFFFFFFFFF2C1C31>0004
--FFFFFFFFFF1715B8>0004
--FFFFFFFFFF231C31>0004
--FFFFFFFFFF3519B6>0001
--FFFFFFFFFF7E198C>0004
--FFFFFFFFFF8F1B87>0001
--- DROPDOWN [11] ---
++FFFFFFFFFF3A15B8>0004
++FFFFFFFFFF8E198C>0004
++FFFFFFFFFF3819B6>0001
++FFFFFFFFFF931B87>0001
++FFFFFFFFFF3F1C31>0004
++FFFFFFFFFFA51C6F>0010
--FFFFFFFFFF2615B8>0004
--FFFFFFFFFF2C1C31>0004
--FFFFFFFFFF3619B6>0001
--FFFFFFFFFF87198C>0004
--FFFFFFFFFF901B87>0001
--- CLOSEUP [12] ---
++FFFFFFFFFF4115B8>0004
++FFFFFFFFFF96198C>0004
++FFFFFFFFFF6B1AC4>0004
++FFFFFFFFFF4E1C31>0004
--FFFFFFFFFF141043>0005
--FFFFFFFFFF3819B6>0001
--FFFFFFFFFF3A15B8>0004
--FFFFFFFFFF3F1C31>0004
--FFFFFFFFFF6A1AC4>0004
--FFFFFFFFFF8E198C>0004
--FFFFFFFFFF931B87>0001
--FFFFFFFFFFFB1A5E>0005
--- DROPDOWN [e] ---
++FFFFFFFFFF161043>0005
++FFFFFFFFFF4515B8>0004
++FFFFFFFFFFA2198C>0004
++FFFFFFFFFF5F19B6>0005
++FFFFFFFFFF1B1A52>0010
++FFFFFFFFFF281A5E>0001
++FFFFFFFFFFBF1B87>0001
++FFFFFFFFFF6C1C31>0004
--FFFFFFFFFF4115B8>0004
--FFFFFFFFFF4E1C31>0004
--FFFFFFFFFF96198C>0004
--- CLOSEUP [13] ---
++FFFFFFFFFF171043>0001
++FFFFFFFFFF4615B8>0004
++FFFFFFFFFFAA198C>0004
++FFFFFFFFFF6019B6>0001
++FFFFFFFFFF291A5E>0005
++FFFFFFFFFF721AC4>0004
++FFFFFFFFFFC01B87>0005
++FFFFFFFFFF7B1C31>0004
--FFFFFFFFFF161043>0005
--FFFFFFFFFF281A5E>0001
--FFFFFFFFFF4515B8>0004
--FFFFFFFFFF5F19B6>0005
--FFFFFFFFFF6B1AC4>0004
--FFFFFFFFFF6C1C31>0004
--FFFFFFFFFFA2198C>0004
--FFFFFFFFFFBF1B87>0001
--- DROPDOWN [13] ---
++FFFFFFFFFF1A1043>0001
++FFFFFFFFFF01112F>0010
++FFFFFFFFFFB6198C>0004
++FFFFFFFFFF6219B6>0001
++FFFFFFFFFF761AC4>0004
++FFFFFFFFFF991C31>0004
--FFFFFFFFFF171043>0001
--FFFFFFFFFF6019B6>0001
--FFFFFFFFFF721AC4>0004
--FFFFFFFFFF7B1C31>0004
--FFFFFFFFFFAA198C>0004
--- CLOSEUP [14] ---
gdi object count permanent grow. visible that object with type 0x10 (this is brush) created but never deleted
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With