この C++/MFC MDI アプリケーションでは、各 MDI クライアント ウィンドウに CDialog に基づくフォームが含まれています。このフォームには、非常に多くのコントロール (数百ものコントロールも含む) を含めることができます。GDI ハンドルが比較的すぐに不足することに気付きました (Windows の制限はプロセスごとに 10000 です)。
主な問題は、ほぼすべてのコントロールに設定したフォントでした。多くの場合、Arial 11 などの複数のコントロールに同じ属性を持つフォントが使用されるため、内部参照カウントを使用してフォントを共有しています。
これは役に立ちましたが、CEdit は他のコントロールとは異なる動作をします。同じ共有フォント ハンドルを複数の CEdit に渡す場合、GDI ハンドルの数は CEdit ごとに 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 が使用され、ハンドルの数は増加しません。
この問題を回避する機会はありますか?