【问题标题】:Can't seem to make double-buffered painting with multiple monitors似乎无法使用多台显示器进行双缓冲绘画
【发布时间】:2012-09-12 08:06:55
【问题描述】:

我正在尝试重新制作用 C++ 和 WinAPI 编写的 Windows 屏幕保护程序,以便在多个显示器上工作。我找到了提供基础知识的this article。但是当我在自己的代码中实现它时,我得到了一个奇怪的结果。看看这段代码:

case WM_PAINT:
{
    PAINTSTRUCT ps = {0};
    HDC hdcE = BeginPaint(hWnd, &ps );

    EnumDisplayMonitors(hdcE, NULL, MyPaintEnumProc, 0);

    EndPaint(hWnd, &ps);
}
break;

BOOL CALLBACK MyPaintEnumProc(
      HMONITOR hMonitor,  // handle to display monitor
      HDC hdc1,     // handle to monitor DC
      LPRECT lprcMonitor, // monitor intersection rectangle
      LPARAM data       // data
      )
{
    MONITORINFO mi = {0};
    mi.cbSize = sizeof(mi);
    if(GetMonitorInfo(hMonitor, &mi))
    {
        //Is it a primary monitor?
        BOOL bPrimary = mi.dwFlags & MONITORINFOF_PRIMARY;

        DoDrawing(bPrimary, hdc1, &mi.rcMonitor);
    }

    return 1;
}

void DoDrawing(BOOL bPrimaryMonitor, HDC hDC, RECT* pRcMonitor)
{
//#define DIRECT_PAINT          //Comment out for double-buffering

    int nMonitorW = abs(pRcMonitor->right - pRcMonitor->left);
    int nMonitorH = abs(pRcMonitor->bottom - pRcMonitor->top);

    HDC hMemDC = ::CreateCompatibleDC(hDC);
    if(hMemDC)
    {
        HBITMAP hMemBmp = ::CreateCompatibleBitmap(hDC, nMonitorW, nMonitorH);
        if(hMemBmp)
        {
            HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hMemBmp);

            COLORREF clr, clrBorder;
            if(bPrimaryMonitor)
            {
                clr = RGB(0, 128, 0);           //Green
                clrBorder = RGB(255, 0, 0);
            }
            else
            {
                clr = RGB(128, 0, 0);           //Red
                clrBorder = RGB(0, 255, 0);

            }

            RECT rcRect;
#ifndef DIRECT_PAINT
            //With double-buffering
            rcRect.left = 0;
            rcRect.top = 0;
            rcRect.right = nMonitorW;
            rcRect.bottom = nMonitorH;
#else
            rcRect = *pRcMonitor;
#endif

            HBRUSH hBrush = ::CreateSolidBrush(clr);

#ifndef DIRECT_PAINT
            //With double-buffering
            ::FillRect(hMemDC, &rcRect, hBrush);
#else
            ::FillRect(hDC, &rcRect, hBrush);
#endif


#ifndef DIRECT_PAINT
            //With double-buffering
            ::BitBlt(hDC, pRcMonitor->left, pRcMonitor->top, nMonitorW, nMonitorH, hMemDC, 0, 0, SRCCOPY);
#endif

//Debugging output
CString _s;
_s.Format(_T("%s\n")
          _T("%s\n")
          _T("hDC=0x%X\n")
          _T("hMemDC=0x%X\n")
        _T("RcMonitor: L=%d, T=%d, R=%d, B=%d")
          , 
          bPrimaryMonitor ? _T("Primary") : _T("Secondary"),
#ifndef DIRECT_PAINT
          _T("Double-buffering"),
#else
          _T("Direct paint"),
#endif
          hDC,
          hMemDC,
          pRcMonitor->left,
          pRcMonitor->top,
          pRcMonitor->right,
          pRcMonitor->bottom);
::DrawText(hDC, _s, _s.GetLength(), pRcMonitor, DT_NOCLIP | DT_NOPREFIX);


            SelectObject(hMemDC, hOldBmp);
            ::DeleteObject(hMemBmp);
        }

        ::DeleteDC(hMemDC);
    }

}

绘画总是在主显示器上工作。但是当我画到辅助显示器时,我只能直接画到它的 DC。当我使用双缓冲技术(将 DIRECT_PAINT 预处理器指令注释掉)时,我只会在应该是红色的辅助显示器上看到黑屏。

我在这里附上两张截图。

第一个使用直接绘画的作品:

然后是双缓冲失败的那个:

任何想法我在这里做错了什么?

【问题讨论】:

  • 您是否检查过FillRect() 和/或BitBlt() 是否返回错误?
  • 刚刚检查过,它们在屏幕保护程序生命周期的任何时候都没有返回 0。
  • 大多数 GDI 函数在返回错误方面完全不可靠。几乎不值得检查。
  • 想一想,MyPaintEnumProc 中的 hdc1 始终为 NULL。所以,你更失败了。
  • 也检查过,hdc1 不为 NULL。但我完全同意,那些 GDI 功能完全不可靠!

标签: c++ winapi gdi screensaver doublebuffered


【解决方案1】:

替换 WM_PAINT 的代码

case WM_PAINT:
   hdc = BeginPaint(hWnd, &ps);
   EnumDisplayMonitors(hdc, NULL, MyPaintEnumProc, 0);
   EndPaint(hWnd, &ps);

case WM_PAINT:
   hdc = GetDC(NULL);
   EnumDisplayMonitors(hdc, NULL, MyPaintEnumProc, 0);
   ReleaseDC(NULL, hdc);

它会起作用的。

看到这个http://msdn.microsoft.com/en-us/library/windows/desktop/dd162610(v=vs.85).aspx

【讨论】:

    猜你喜欢
    • 2015-04-23
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 2011-02-20
    • 2010-10-09
    • 1970-01-01
    相关资源
    最近更新 更多