windows BitBlt 忽略 CAPTUREBLT 并且似乎总是捕获目标的缓存副本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2899655/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
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.
我正在尝试使用 BitBlt 函数捕获屏幕截图。但是,每次我截取屏幕截图时,无论我做什么,非客户区都不会改变。就好像它正在获取它的一些缓存副本。客户区被正确捕获。
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:
此外,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;
}
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:
大部分代码来自 Qt 的 QWidget::grabWindow 函数,因为我想进行一些更改以使其更加灵活。Qt 的文档指出:
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.
grabWindow() 函数从屏幕上而不是从窗口中抓取像素,即如果有另一个窗口部分或全部覆盖在您抓取的窗口上,您也可以从覆盖的窗口中获取像素。
However, I experience the exact opposite... regardless of the CAPTUREBLT flag. I've tried everything I can think of... nothing works. Any ideas?
但是,我遇到了完全相反的情况……无论 CAPTUREBLT 标志如何。我已经尝试了所有我能想到的......没有任何效果。有任何想法吗?
采纳答案by Serge Dundich
Your confusion about BitBltwith CAPTUREBLTbehaviour comes from the fact that official BitBltdocumentation is unclear and misleading.
您对BitBlt与CAPTUREBLT行为的混淆来自于官方BitBlt文档不明确且具有误导性这一事实。
It states that
"CAPTUREBLT -- Includes any windows that are layered on top of your window in the resulting image. By default, the image only contains your window."
它指出
“CAPTUREBLT - 包括在结果图像中位于窗口顶部的任何窗口。默认情况下,图像仅包含您的窗口。”
What actually means (at least for any windows OS without Aero enabled) "CAPTUREBLT -- Includes any layered(!) windows (see WS_EX_LAYERED extended window style) that overlap your window. Non-layered windows that overlap your window is never included."
实际意味着什么(至少对于没有启用 Aero 的任何 Windows 操作系统) “CAPTUREBLT - 包括与您的窗口重叠的任何分层(!)窗口(请参阅 WS_EX_LAYERED 扩展窗口样式)。与您的窗口重叠的非分层窗口永远不会包括在内。”
Windows without WS_EX_LAYEREDextended window style that overlap your window is not included with or without CAPTUREBLTflag (at least for any windows OS without Aero enabled).
不包含与窗口重叠的WS_EX_LAYERED扩展窗口样式的Windows不包含或不包含CAPTUREBLT标志(至少对于任何未启用 Aero 的 Windows 操作系统)。
QT developers also misunderstood BitBlt/CAPTUREBLT documentation so QT documentation is actually wrong about QPixmap::grabWindow behaviour on WIN32 platform without Aero enabled.
QT 开发人员也误解了 BitBlt/CAPTUREBLT 文档,因此 QT 文档实际上关于 WIN32 平台上未启用 Aero 的 QPixmap::grabWindow 行为是错误的。
ADD:
添加:
If you want to capture your window as it is on the screen you have to capture the entire desktop with CAPTUREBLT flag and then extract the rectangle with your window. (QT developers should do the same thing). It will work correctly in both cases: with and without Aero enabled/available.
如果您想捕获屏幕上的窗口,您必须使用 CAPTUREBLT 标志捕获整个桌面,然后用您的窗口提取矩形。(QT 开发人员应该做同样的事情)。它在两种情况下都能正常工作:启用和不启用 Aero 或不启用 Aero。
回答by Fernando Diaz Toledano
I capture all screen and obtains the same results... :(
我捕获所有屏幕并获得相同的结果...... :(
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);