我在我们庞大的应用软件中发现了GDI泄漏。
下面是一个测试此问题的简单程序。 想法是主对话框打开另一个对话框(对话框A)。 如果对话框A包含CStatic控件的位图功能, 它会造成GDI泄漏。
即使我使用“DeleteObject(bitmap)”。
我做错了什么吗? 你有什么想法吗?
感谢。
// Resource File
...
DIALOG_BOXA DIALOGEX 0, 0, 219, 142
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_BORDER
EXSTYLE WS_EX_STATICEDGE
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,46,121,50,14
PUSHBUTTON "Cancel",IDCANCEL,119,121,50,14
CONTROL 131,RED_LIGHT0,"Static",SS_BITMAP,7,17,80,37
PUSHBUTTON "",RED_LIGHT1,7,60,80,37,BS_BITMAP | NOT WS_TABSTOP
END
// head file
DialogBoxA: public CDialog
{
...
CStatic m_static;
CButton m_button ;
...
}
/////////////////////////////////////////////////////////
void DialogBoxA::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, RED_LIGHT0, m_static);
DDX_Control(pDX, RED_LIGHT1, m_button);
}
BOOL DialogBoxA::OnInitDialog()
{
CDialog::OnInitDialog();
HBITMAP bitmap ;
// This will create GDI leak !!!
bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_static.SetBitmap (bitmap );
DeleteObject(bitmap);
// This is OK !!!
bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_button.SetBitmap (bitmap );
DeleteObject(bitmap);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
答案 0 :(得分:1)
以下是静态控制中GDI泄漏的exlanantion和解决方案: http://blogs.msdn.com/b/oldnewthing/archive/2014/02/19/10501282.aspx
答案 1 :(得分:0)
这很复杂。首先,让我们仔细看看您的代码
bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_static.SetBitmap (bitmap );
DeleteObject(bitmap);
您应该不删除您刚刚告诉静态控件使用的位图。它还在使用它!在您将位图设置为其他内容之前,它将继续使用它。
因此,不要在对话框初始化期间尝试删除位图,而应该等到对话框被销毁。此时,您必须告诉静态控件停止使用位图,然后才能删除位图对象。
其次,静态控件有时会复制您的位图。它是否复制取决于一堆事物,包括位图是否具有非零alpha通道。破坏此副本也成为您的问题。 (这可能就是为什么你的一个案件有效,另一个没有。)
您基本上必须跟踪您认为设置的位图,直到清理它为止。然后你必须比较静态控件中的实际内容与你认为的那个。如果它们不同,则会破坏它们(您的位图和静态控件副本)。如果它们相同,那么静态控件不会复制,你必须销毁你制作的那个(一次!)。