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 в значительной степени использует метод Save Gdi :: Bitmap. Он был опущен, потому что у него есть некоторый специфичный для приложения код, который не имеет отношения к примеру. Также дополнительным бонусом является то, что если вам интересно, как включить курсор в скриншот, то код также там. Надеюсь, поможет. Также стоит упомянуть, что в отличие от традиционного подхода, это также будет включать любые наложенные окна, которые вы можете иметь поверх захваченного окна. Кроме того, если вы используете этот код для полноэкранного захвата, имейте в виду, что он не будет захватывать окна видеоигр. Мне действительно интересно, как сделать это правильно, не прибегая к DirectX. Это влияет только на Windows Vista / 7 при работе в режиме Aero.