BitBlt ignores CAPTUREBLT and seems to always capture a cached copy of the target...
- by Jake Petroules
I am trying to capture screenshots using the BitBlt function. However, every single time I capture a screenshot, the non-client area NEVER changes no matter what I do. It's as if it's getting some cached copy of it. The client area is captured correctly.
If I close and then re-open the window, and take a screenshot, the non-client area will be captured as it is. Any subsequent captures after moving/resizing the window have no effect on the captured screenshot. Again, the client area will be correct.
Furthermore, the CAPTUREBLT flag seems to do absolutely nothing at all. I notice no change with or without it. Here is my capture code:
QPixmap WindowManagerUtils::grabWindow(WId windowId, GrabWindowFlags flags, int x, int y, int w, int h)
{
RECT r;
switch (flags)
{
case WindowManagerUtils::GrabWindowRect:
GetWindowRect(windowId, &r);
break;
case WindowManagerUtils::GrabClientRect:
GetClientRect(windowId, &r);
break;
case WindowManagerUtils::GrabScreenWindow:
GetWindowRect(windowId, &r);
return QPixmap::grabWindow(QApplication::desktop()->winId(), r.left, r.top, r.right - r.left, r.bottom - r.top);
case WindowManagerUtils::GrabScreenClient:
GetClientRect(windowId, &r);
return QPixmap::grabWindow(QApplication::desktop()->winId(), r.left, r.top, r.right - r.left, r.bottom - r.top);
default:
return QPixmap();
}
if (w < 0)
{
w = r.right - r.left;
}
if (h < 0)
{
h = r.bottom - r.top;
}
#ifdef Q_WS_WINCE_WM
if (qt_wince_is_pocket_pc())
{
QWidget *widget = QWidget::find(winId);
if (qobject_cast<QDesktopWidget*>(widget))
{
RECT rect = {0,0,0,0};
AdjustWindowRectEx(&rect, WS_BORDER | WS_CAPTION, FALSE, 0);
int magicNumber = qt_wince_is_high_dpi() ? 4 : 2;
y += rect.top - magicNumber;
}
}
#endif
// Before we start creating objects, let's make CERTAIN of the following so we don't have a mess
Q_ASSERT(flags == WindowManagerUtils::GrabWindowRect || flags == WindowManagerUtils::GrabClientRect);
// Create and setup bitmap
HDC display_dc = NULL;
if (flags == WindowManagerUtils::GrabWindowRect)
{
display_dc = GetWindowDC(NULL);
}
else if (flags == WindowManagerUtils::GrabClientRect)
{
display_dc = GetDC(NULL);
}
HDC bitmap_dc = CreateCompatibleDC(display_dc);
HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h);
HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
// copy data
HDC window_dc = NULL;
if (flags == WindowManagerUtils::GrabWindowRect)
{
window_dc = GetWindowDC(windowId);
}
else if (flags == WindowManagerUtils::GrabClientRect)
{
window_dc = GetDC(windowId);
}
DWORD ropFlags = SRCCOPY;
#ifndef Q_WS_WINCE
ropFlags = ropFlags | CAPTUREBLT;
#endif
BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, ropFlags);
// clean up all but bitmap
ReleaseDC(windowId, window_dc);
SelectObject(bitmap_dc, null_bitmap);
DeleteDC(bitmap_dc);
QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap);
DeleteObject(bitmap);
ReleaseDC(NULL, display_dc);
return pixmap;
}
Most of this code comes from Qt's QWidget::grabWindow function, as I wanted to make some changes so it'd be more flexible. Qt's documentation states that:
The grabWindow() function grabs pixels
from the screen, not from the window,
i.e. if there is another window
partially or entirely over the one you
grab, you get pixels from the
overlying window, too.
However, I experience the exact opposite... regardless of the CAPTUREBLT flag. I've tried everything I can think of... nothing works. Any ideas?