GDI 资源泄漏

Posted

技术标签:

【中文标题】GDI 资源泄漏【英文标题】:GDI Resource Leak 【发布时间】:2014-02-10 09:15:36 【问题描述】:

我在我们庞大的应用软件中发现了 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

【问题讨论】:

你如何确定有泄漏? 另外,MSDN 声明您应该使用 LoadImage 而不是 LoadBitmap ...您尝试过更改吗? 感谢您的回复。是的,我使用“GDIView”和“Windows 任务管理器”来监控这个,我发现打开“DialogBoxA”后“GDI 对象”增加了。 谢谢,我试试“LoadImage”,同样的问题。 打开对话框时 GDI 对象应该增加。尝试注释掉你的代码行,你可能会发现它做同样的事情......你认为他们如何绘制这些按钮等!?? 【参考方案1】:

下面是静态控制中GDI泄漏的解释和解决方法: http://blogs.msdn.com/b/oldnewthing/archive/2014/02/19/10501282.aspx

【讨论】:

【参考方案2】:

这很复杂。首先,让我们仔细看看你的代码

bitmap = LoadBitmap ( AfxGetApp()->m_hInstance,BEACON_BIG_RED_ON) ;
m_static.SetBitmap (bitmap );
DeleteObject(bitmap);

您应该删除您刚刚告诉静态控件使用的位图。它还在使用它!它将继续使用它,直到您将位图设置为其他内容。

因此,与其在对话框初始化期间尝试删除位图,不如等到对话框被销毁。此时,您必须告诉静态控件停止使用位图,然后才能删除位图对象。

第二,静态控件有时会复制您的位图。是否制作副本取决于很多事情,包括位图是否具有非零 Alpha 通道。销毁此副本也成为您的问题。 (这可能就是您的一个案例有效而另一个无效的原因。)

您基本上必须跟踪您认为自己设置的位图,直到需要清理为止。然后,您必须将静态控件中的实际内容与您认为给它的内容进行比较。如果它们不同,那么您将两者都销毁(您的位图和静态控件副本)。如果它们相同,则静态控件没有复制,您只需销毁您制作的副本(一次!)。

【讨论】:

以上是关于GDI 资源泄漏的主要内容,如果未能解决你的问题,请参考以下文章

一个进程的 GDI 泄漏会影响其他进程吗?

如何在 Windows 窗体中创建 GDI 泄漏!

没有 GDI 泄漏的 VB6 内存泄漏

防止 WPF 中的内存泄漏

如何调试 GDI 对象泄漏?

GDI-句柄泄漏