【问题标题】:MFC drawn elements change after 30-60 minutesMFC 绘制的元素在 30-60 分钟后发生变化
【发布时间】:2013-04-01 06:02:26
【问题描述】:

我有一个具有完全自定义绘制的 UI 的应用程序(即只是一堆带有文本的填充框)。运行大约 30-60 分钟后,UI 元素会自发变化。例如,白线(框边框)消失,文本调整大小等。

我已链接到其中一个屏幕的前后图像。这表明所有的白线都消失了。其他屏幕显示文本大小发生显着变化。

之前:http://s21.postimg.org/cogqodson/BEFORE.png

之后:http://s24.postimg.org/7skx21sid/AFTER.png

本项目使用 MFC 用 MS Visual C++ 2010 编写,并在 Windows 7 Pro 上运行。

这是我的 OnPaint() 代码:

void CMainWindow::OnPaint()
{
    CPaintDC dcScreen( this );
    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap( &dcScreen, m_rect.Width(), m_rect.Height() );

    CDC dc;
    dc.CreateCompatibleDC( &dcScreen );
    CBitmap* pOldBitMap = dc.SelectObject( &bitmap );

    dc.FillRect(m_rect, &BGBRUSH);
    int bkmode = dc.SetBkMode(TRANSPARENT);
    dc.SelectObject(&BGBRUSH);

    CPen brightwhitepen(PS_SOLID, 5, RGB(255,255,255));
    CPen* pOldPen = dc.SelectObject(&brightwhitepen);

    // draw some stuff:
    // dc.Rectangle, dc.DrawText, etc.
    // ...

    // Blit the memory device context to the screen device context
    dcScreen.BitBlt
        (
        0, 
        0, 
        m_rect.Width(), 
        m_rect.Height(),
        &dc, 
        0, 
        0, 
        SRCCOPY
        );

    dc.SetBkMode( bkmode );     // Restore old background mode
    dc.SelectObject( pOldPen ); // reselect old pen
    dc.SelectObject( pOldBitMap ); // Restore old bitmap
}

以前有没有人见过这种奇怪的行为?关于在哪里进行调查的任何提示?

谢谢!

【问题讨论】:

  • 我怀疑你并没有完全释放你的资源,而且每次调用都会泄漏。在某一点之后,它只是开始无法分配新的笔、位图等......但我不确定你如何使用所有 MFC 包装类来处理 win32 原语句柄。检查 tack manager 并查看您的进程在内存方面做了什么。也许 Process Explorer 允许您查看打开句柄的数量?
  • 这也是我最初的想法,但是如果我看任务管理器,内存使用情况很好。事实上,在我上次的测试中,在 UI 混乱之前和之后的内存使用情况是完全一样的。
  • 消除绘图代码直到问题消失,在任务管理器中查看 gdi 句柄计数而不是内存使用情况 - 不确定该列的实际名称,可能不同
  • 是的!谢谢“cppguy”和“marcin_j”!对于一个特殊项目,我使用 GDI 函数来创建我的笔(“ExtCreatePen()”)而不是 MFC 类,当然,我忘记为该对象调用“DeleteObject()”。在您的指导下,我能够看到任务管理器中的“GDI 对象”计数在 55 分钟内攀升至 10000,此时它会达到最大值,并且 UI 将停止正确绘制。再次感谢!!!

标签: c++ winapi mfc gdi


【解决方案1】:

之前我曾解决过类似的问题,当时我忘记恢复其中一个 GDI 句柄的状态。解决方案是使用SaveDCRestoreDC,这意味着您在处理完这些对象后不必恢复DC 中的任何对象。您可以在此处下载really convenient RAII class,它会为您完成所有工作。

次要建议是使用库存对象和内置 DC 句柄,而不是自己创建。所以替换你的brightwhitepen 代码如下:

dc.SetDCPenColor(RGB(255,255,255));
CPen* pBrightwhitepen = CPen::FromHandle((HPEN)GetStockObject(DC_PEN));

dc.SetDCBrushColor(RGB(0,0,255));
CBrush* pBgBrush = CBrush::FromHandle((HBRUSH)GetStockObject(DC_BRUSH));

现在使用这两个指针来绘制你的东西。优点是您没有分配任何东西,因此您不会泄漏任何东西,并且调用不会失败,因为库存对象始终存在。

【讨论】:

    猜你喜欢
    • 2015-06-21
    • 2016-12-17
    • 2022-06-28
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 2011-10-28
    • 2021-10-11
    相关资源
    最近更新 更多