如何正确抓屏对航空/ DWM一个特定的窗口
-
18-09-2019 - |
题
背景信息: 我有这样的MFC应用程序我编写,并使用了很长时间,当用户点击打印屏幕/ Alt + Print Screen键几乎自动保存截图到硬盘一直。我一直在推迟使用任何相关的航空到现在为止,我已经使用Windows 7 RC的几个星期了。
的问题: 我使用的是标准的GetDC / BitBlt的方法来捕获窗口的内容。我有这种方法没有问题,同时定期做全屏幕抓斗(无论多少窗口的打开方式等)。当我尝试捕获前台窗口(ALT + PRINTSCREEN),就会出现问题。下面是两个例子:
实施例1 http://indiecodelabs.com/extern/example1.jpg
实施例2 http://indiecodelabs.com/extern/example2.jpg
正如你所看到的,我收到的垃圾,其中的边界应该是。这是接近顶部,在这里我们可以看到在两个屏幕截图工具栏上有一些重复更明显。
我一直在谷歌上搜索现在这个几个小时,所有我能找到的文章说,DWM下BitBtl / GetDC的方法是行不通的,但无法找到一个单一的一个解释我们(开发商)应你要能够在DWM运行时保持在我们的应用程序相同的功能。
任何帮助,指针,建议将不胜感激。
解决方案
这是我unfortuneatly不知道确切的答案,以一个非常好的问题。我的第一个想法是抓住了整个台式机和切有趣的部分出来。
我已经挖成QT 4.5来源,看看他们是如何做到这一点,并发现这样的事情。如果切换到GetClientRect和GetWindowRect剥离QT样板代码,你应该得到你想要的。它看起来像一个黑客虽然:)
QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
{
RECT r;
GetClientRect(winId, &r);
if (w < 0) w = r.right - r.left;
if (h < 0) h = r.bottom - r.top;
// Create and setup bitmap
HDC display_dc = GetDC(0);
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 = GetDC(winId);
BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, SRCCOPY);
// clean up all but bitmap
ReleaseDC(winId, window_dc);
SelectObject(bitmap_dc, null_bitmap);
DeleteDC(bitmap_dc);
QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap);
DeleteObject(bitmap);
ReleaseDC(0, display_dc);
return pixmap;
}
其他提示
BOOL CaptureWindow(const CString& filename)
{
HWND hWnd = NULL;
hWnd = ::GetForegroundWindow();
if(!hWnd)
{
return FALSE;
}
CRect rect;
GetWindowRect(hWnd, &rect);
rect.NormalizeRect();
return DoCapture(CPoint(rect.left, rect.top), CSize(rect.Width(), rect.Height()), filename);
}
BOOL DoCapture(const POINT& coords, const SIZE& areaSize, const CString& filename)
{
CDC dc;
HDC hdc = GetDC(NULL); // <-- We use this instead of GetWindowDC.
// This is the only thing I had to change other than
// getting the window coordinates in CaptureWindow()
dc.Attach(hdc);
// Create a memory DC into which the bitmap will be captured
CDC memDC;
memDC.CreateCompatibleDC(&dc);
// If there is already a bitmap, delete it as we are going to replace it
CBitmap bmp;
bmp.DeleteObject();
ICONINFO info;
GetIconInfo((HICON)::GetCursor(), &info);
CURSORINFO cursor;
cursor.cbSize = sizeof(CURSORINFO);
GetCursorInfo(&cursor);
bmp.CreateCompatibleBitmap(&dc, areaSize.cx, areaSize.cy);
CBitmap * oldbm = memDC.SelectObject(&bmp);
// Before we copy the image in, we blank the bitmap to
// the background fill color
memDC.FillSolidRect(&CRect(0,0,areaSize.cx, areaSize.cy), RGB(255,255,255));
// Copy the window image from the window DC into the memory DC
memDC.BitBlt(0, 0, areaSize.cx, areaSize.cy, &dc, coords.x, coords.y, SRCCOPY|CAPTUREBLT);
// This part captures the mouse cursor and paints it on the image.
if(programSettings.bWantCursor)
{
int osVersion = OSCheck::GetMajorOSVersion(); // For some reason cursor icons in
// versions older than Vista are not
// top-aligned. So we compensate.
int offsetX = (osVersion >= 6) ? 0 : 10;
int offsetY = (osVersion >= 6) ? 0 : 10;
CPoint cursorOffset(cursor.ptScreenPos.x - coords.x - offsetX, cursor.ptScreenPos.y - coords.y - offsetY);
// Now draw the image of the cursor that we captured during
// the mouse move. DrawIcon will draw a cursor as well.
memDC.DrawIcon(cursorOffset, (HICON)cursor.hCursor);
}
memDC.SelectObject(oldbm);
Bitmap outputBitMap(bmp, NULL);
// Optionally copy the image to the clipboard.
if(programSettings.bWantClipboard)
{
if(OpenClipboard(NULL))
{
EmptyClipboard();
SetClipboardData(CF_BITMAP, bmp);
CloseClipboard();
}
}
BOOL success = DumpImage(&outputBitMap, filename);
DeleteObject(bmp.Detach());
DeleteDC(dc.Detach());
DeleteDC(memDC.Detach());
return success;
}
有关参考:DumpImage几乎使用GDI ::位图的保存方法。因为它有一些特定的应用程序代码是不相关的例子已经省略。还有一个好处是,如果你想知道如何在您的screengrab光标然后代码也有。希望能帮助到你。另外值得一提的是,违背了传统的做法,这也将包括任何重叠的窗口,你可能对捕获窗口的顶部。另外,如果您使用全屏幕捕获这个代码,被警告说,它不会捕获视频游戏窗口。实际上,我不知道怎么做正确,而不必诉诸到DirectX。这仅在航空模式下运行时影响Windows Vista / 7的