我正在尝试使用BitBlt功能捕获屏幕截图。但是,每次我捕获屏幕截图时,无论我做什么,非客户区都不会改变。就好像它正在获得它的一些缓存副本。正确捕获客户区。
如果我关闭然后重新打开窗口并截取屏幕截图,非客户区域将按原样捕获。移动/调整窗口大小后的任何后续捕获都不会对捕获的屏幕截图产生影响。同样,客户区域也是正确的。
此外,CAPTUREBLT标志似乎完全没有任何作用。我注意到有或没有变化。这是我的捕获代码:
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;
}
这些代码大部分来自Qt的QWidget :: grabWindow函数,因为我想进行一些更改,因此它更灵活。 Qt的文档说明:
grabWindow()函数抓取像素 从屏幕,而不是从窗口, 即如果有另一个窗口 部分或完全超过你 抓住,你得到像素 覆盖窗户。
但是,无论CAPTUREBLT标志如何,我都会遇到完全相反的情况。我已经尝试了所有我能想到的......没有用。有什么想法吗?
答案 0 :(得分:7)
您对 BitBlt 与 CAPTUREBLT 行为的混淆来自官方 BitBlt 文档不清楚且具误导性这一事实。
它说明了 “CAPTUREBLT - 包括在生成的图像中分层放置在窗口顶部的任何窗口。默认情况下,图像仅包含您的窗口。”
实际意味着什么(至少对于没有启用Aero的任何Windows操作系统) “CAPTUREBLT - 包含与窗口重叠的任何分层(!)窗口(请参阅WS_EX_LAYERED扩展窗口样式)。从不包含与窗口重叠的非分层窗口。”
没有 WS_EX_LAYERED 扩展窗口样式与Windows窗口重叠的窗口不包括 CAPTUREBLT 标记(至少对于没有启用Aero的任何Windows操作系统)。
QT开发人员也误解了BitBlt / CAPTUREBLT文档,因此在未启用Aero的情况下,Q32文档在WIN32平台上的QPixmap :: grabWindow行为实际上是错误的。
添加强>
如果要捕获屏幕上的窗口,则必须使用CAPTUREBLT标记捕获整个桌面,然后使用窗口提取矩形。 (QT开发人员应该做同样的事情)。它可以在两种情况下正常工作:启用和不启用Aero。
答案 1 :(得分:0)
我捕获所有屏幕并获得相同的结果...... :(
const uint SRCCOPY = 0x00CC0020; //SRCCOPY
const uint CAPTUREBLT = 0x00CC0020 | 0x40000000; //CAPTUREBLT
bool dv = BitBlt(hCaptureDC, 0, 0, Bounds.Width, Bounds.Height,
hDesktopDC, Bounds.Left, Bounds.Top, _with_tooltips ? CAPTUREBLT : SRCCOPY);