Odd MFC/GDI behaviour (blank image) that doesn'

2019-08-01 08:29发布

问题:

There is this weird bug in my program that I'm trying to fix, but I'm really at a loss for what it could be. This part of my program has a dialog which shows previews of various items using MFC/GDI. When I scroll through different items, sometimes the preview image just disappears and goes blank. However, it:

  • Only happens on some machines
  • Apparently happens on both Windows 7 and XP
  • Doesn't happen on the same item every time
  • Item IS STILL THERE when one takes a screenshot, but it is blank when viewing it normally.
  • Seems to happen at random places throughout the code when I'm attempting to trace through it with breakpoints. It's not always in the same location that the screen goes from image to blank, which leads me to believe that it's not happening in the same thread as my main thread, even though that's really the only thread that's not blocked at that point. That means that it's happening in a windows thread or something, doesn't it?

I'm assuming it's a race condition of some sort, but the behaviour of the preview in screenshots, in particular, rather confuses me. Why would it be fine when taking a screenshot but be blank when viewing it on screen? Is there some mechanic of the "printscreen" that bypasses what's displyed or updated on the screen?

I realize that I haven't given much information and that people obviously can't help much, but if anyone could think of ANYTHING, it would be much appreciated :)

Thanks!

回答1:

Another theory: GDI resource leak

If you forget to free your GDI objects, weird things start to happen - including unpainted areas.

  1. Run taskmgr.exe and add the "GDI Objects" column.
  2. Run your software and monitor the GDI object count. Does it stabilize?
  3. If your GDI Object count does not stabilize, look in your relevant WM_PAINT handlers.

Here's an example of a GDI leak:

void CMyWnd::OnPaint()
{
    CPaintDC dc(this);
    dc.SelectObject(&font);
}

Selected GDI objects must always be deselected:

void CMyWnd::OnPaint()
{
    CPaintDC dc(this);
    CFont *pOldFont = dc.SelectObject(&font);
    // Use font
    dc.SelectObject(pOldFont);
}


回答2:

When you record your screen, are you reading the desktop using GDI apis? In that case, any hardware-accelerated surface may become black (or possibly white). To test this, you can disable hardware acceleration for your graphics card. If your recorder starts working then you've found the culprit!

To record these non-GDI surfaces you probably need to read the surface using DirectX/OpenGL. I would start with this article: http://www.codeproject.com/KB/dialog/screencap.aspx