我正在尝试使用BitBlt函数捕获截图。 但是,每次我捕捉屏幕截图时,无论我做什么,非客户端区域都不会改变。 就好像它正在获取一些caching副本。 客户区被正确捕获。
如果我closures然后重新打开窗口,并截图,非客户区将被捕获,因为它是。 移动/调整窗口大小后的任何后续捕获都不会影响捕获的屏幕截图。 再次,客户区将是正确的。
而且,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标志。 我尝试了所有我能想到的…没有任何工作。 有任何想法吗?
BitBlt与CAPTUREBLT行为的混淆来自于官方BitBlt文档不清楚和误导的事实。
它指出
“CAPTUREBLT – 在结果图像中包含窗口顶部的任何窗口。默认情况下,图像只包含窗口。”
实际上意味着什么(至少对于没有启用Aero的任何Windows操作系统) “CAPTUREBLT – 包含与窗口重叠的任何分层(!)窗口(参见WS_EX_LAYERED扩展窗口样式),不包含与窗口重叠的非分层窗口。
没有WS_EX_LAYERED扩展窗口样式的窗口不包含有或没有CAPTUREBLT标志(至少对于没有启用Aero的任何Windows操作系统)。
QT开发人员也误解了BitBlt / CAPTUREBLT文档,所以QT文档实际上在WIN32平台上没有启用Aero的QPixmap :: grabWindow行为是错误的。
加:
如果你想捕获你的窗口,因为它是在屏幕上,你必须用CAPTUREBLT标志捕捉整个桌面,然后用你的窗口提取矩形。 (QT开发者应该做同样的事情)。 它会在两种情况下正常工作:启用/不启用Aero。
我捕捉所有的屏幕,并获得相同的结果… 🙁
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);