在我们的 C++/MFC MDI 应用程序中,每个 MDI 客户端窗口都包含一个基于 CDialog 的窗体,该窗体可以包含非常多的控件,甚至数百个。我们注意到我们用完 GDI 句柄的速度相对较快(Windows 限制为每个进程 10000 个)。
主要问题是我们在几乎每个控件上设置的字体。通常具有相同属性的字体用于多个控件,例如 Arial 11,因此我们现在共享字体,并带有内部引用计数。
这有所帮助,但是 CEdit 的行为与其他控件不同。将相同的共享字体句柄传递给多个 CEdit 时,每个 CEdit 的 GDI 句柄数仍会增加 1。
BOOL CGDIHandlesTestDlg::OnInitDialog()
{
__super::OnInitDialog();
m_font.CreatePointFont(-50, _T("Arial"));
int x = 0, y = 0;
for (int i = 0; i < 100; i++)
{
CRect rc(CPoint(x, y), CSize(10, 10));
CEdit* pEdit = new CEdit();
if (!pEdit->Create(WS_CHILD|WS_BORDER|WS_VISIBLE, rc, this, 1000+i))
break;
pEdit->SetFont(&m_font); // CREATES A NEW GDI OBJECT!!!
DWORD dwCount = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
TRACE(_T("%d\n"), dwCount); // dwCount is incremented on each iteration
x += 10;
}
return TRUE
}
m_font 是一个共享的 CFont 实例并声明为 CDialog 成员。
在每次迭代中,即使将相同的字体实例传递给 SetFont,dwCount 也会增加。好像 CEdit 创建了字体的影子副本。
甚至 pEdit->SetFont(NULL) 也会增加 gdi 句柄的数量!
使用其他控件类型,例如 CStatic,一切都很好。
它也与 comctl32.dll 的版本有关,使用 6.0 版本时行为可重现:
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
如果省略该行,则使用 comctl32.dll 5.8,句柄数不会增加。
我们有机会解决这个问题吗?