Reputation: 30885
How can I take a screenshot of the current screen using Win32?
Upvotes: 63
Views: 113720
Reputation: 5130
HDC hScreenDC = GetDC(nullptr);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int width = GetDeviceCaps(hScreenDC,HORZRES);
int height = GetDeviceCaps(hScreenDC,VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC,width,height);
HBITMAP hOldBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,hBitmap));
BitBlt(hMemoryDC,0,0,width,height,hScreenDC,0,0,SRCCOPY);
hBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,hOldBitmap));
DeleteDC(hMemoryDC);
DeleteDC(hScreenDC);
Upvotes: 72
Reputation: 21532
Full code for saving a raw 24-bit bitmap of all monitors at the current window station using Windows API:
BOOL WINAPI SaveBitmap(WCHAR *wPath)
{
BITMAPFILEHEADER bfHeader;
BITMAPINFOHEADER biHeader;
BITMAPINFO bInfo;
HGDIOBJ hTempBitmap;
HBITMAP hBitmap;
BITMAP bAllDesktops;
HDC hDC, hMemDC;
LONG lWidth, lHeight;
BYTE *bBits = NULL;
HANDLE hHeap = GetProcessHeap();
DWORD cbBits, dwWritten = 0;
HANDLE hFile;
INT x = GetSystemMetrics(SM_XVIRTUALSCREEN);
INT y = GetSystemMetrics(SM_YVIRTUALSCREEN);
ZeroMemory(&bfHeader, sizeof(BITMAPFILEHEADER));
ZeroMemory(&biHeader, sizeof(BITMAPINFOHEADER));
ZeroMemory(&bInfo, sizeof(BITMAPINFO));
ZeroMemory(&bAllDesktops, sizeof(BITMAP));
hDC = GetDC(NULL);
hTempBitmap = GetCurrentObject(hDC, OBJ_BITMAP);
GetObjectW(hTempBitmap, sizeof(BITMAP), &bAllDesktops);
lWidth = bAllDesktops.bmWidth;
lHeight = bAllDesktops.bmHeight;
DeleteObject(hTempBitmap);
bfHeader.bfType = (WORD)('B' | ('M' << 8));
bfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
biHeader.biSize = sizeof(BITMAPINFOHEADER);
biHeader.biBitCount = 24;
biHeader.biCompression = BI_RGB;
biHeader.biPlanes = 1;
biHeader.biWidth = lWidth;
biHeader.biHeight = lHeight;
bInfo.bmiHeader = biHeader;
cbBits = (((24 * lWidth + 31)&~31) / 8) * lHeight;
hMemDC = CreateCompatibleDC(hDC);
hBitmap = CreateDIBSection(hDC, &bInfo, DIB_RGB_COLORS, (VOID **)&bBits, NULL, 0);
SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, lWidth, lHeight, hDC, x, y, SRCCOPY);
hFile = CreateFileW(wPath, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
DeleteObject(hBitmap);
return FALSE;
}
WriteFile(hFile, &bfHeader, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
WriteFile(hFile, &biHeader, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
WriteFile(hFile, bBits, cbBits, &dwWritten, NULL);
FlushFileBuffers(hFile);
CloseHandle(hFile);
DeleteDC(hMemDC);
ReleaseDC(NULL, hDC);
DeleteObject(hBitmap);
return TRUE;
}
Upvotes: 12
Reputation: 490038
GetDC(NULL);
to get a DC for the entire screen. CreateCompatibleDC
to create a DC compatible with the screen DC.CreateCompatibleBitmap
to create a bitmap compatible with the screen DC to hold the result.SelectObject
to select the compatible bitmap into the compatible DC.BitBlt
to copy from the screen DC to the compatible DC.SelectObject
to deselect the compatible bitmap from the compatible DC.DeleteDC
to delete the compatible DC.When you create the compatible bitmap, you want it compatible with the screen DC, not the compatible DC.
For example:
HDC dcScreen = GetDC(0);
HDC dcTarget = CreateCompatibleDC(dcScreen);
HBITMAP bmpTarget = CreateCompatibleBitmap(dcScreen);
HGDIOBJ oldBmp = SelectObject(dcTarget, bmpTarget);
BitBlt(dcTarget, 0, 0, cx, cy, dcDesktop, x, y, SRCCOPY | CAPTUREBLT);
SelectObject(dcTarget, oldBmp);
DeleteDC(dcTarget);
ReleaseDC(dcScreen);
The other important part is to get the size, and location, of the entire virtual screen:
int x = GetSystemMetrics(SM_XVIRTUALSCREEN); //left (e.g. -1024)
int y = GetSystemMetrics(SM_YVIRTUALSCREEN); //top (e.g. -34)
int cx = GetSystemMetrics(SM_CXVIRTUALSCREEN); //entire width (e.g. 2704)
int cy = GetSystemMetrics(SM_CYVIRTUALSCREEN); //entire height (e.g. 1050)
Upvotes: 37
Reputation: 6894
There is a MSDN sample, Capturing an Image, for capturing an arbitrary HWND to a DC (you could try passing the output from GetDesktopWindow to this). But how well this will work under the new desktop compositor on Vista/Windows 7, I don't know.
Upvotes: 6
Reputation: 1197
void GetScreenShot(void)
{
int x1, y1, x2, y2, w, h;
// get screen dimensions
x1 = GetSystemMetrics(SM_XVIRTUALSCREEN);
y1 = GetSystemMetrics(SM_YVIRTUALSCREEN);
x2 = GetSystemMetrics(SM_CXVIRTUALSCREEN);
y2 = GetSystemMetrics(SM_CYVIRTUALSCREEN);
w = x2 - x1;
h = y2 - y1;
// copy screen to bitmap
HDC hScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, w, h);
HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
BOOL bRet = BitBlt(hDC, 0, 0, w, h, hScreen, x1, y1, SRCCOPY);
// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();
// clean up
SelectObject(hDC, old_obj);
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
DeleteObject(hBitmap);
}
Upvotes: 29