I want to take screenshots of a window which has no focus. My function works for some windows but not for all and I don't know why. I tried it to capture the window of Bluestacks App Player and it works perfectly. But for Nox App Player and some other games it doesn't work at all. I just get a black image with the size of the window.
Here is the code so far:
void screenshot_window(HWND handle) {
RECT client_rect = { 0 };
GetClientRect(handle, &client_rect);
int width = client_rect.right - client_rect.left;
int height = client_rect.bottom - client_rect.top;
HDC hdcScreen = GetDC(handle);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, width, height);
SelectObject(hdc, hbmp);
BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY);
BITMAPINFO bmp_info = { 0 };
bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
bmp_info.bmiHeader.biWidth = width;
bmp_info.bmiHeader.biHeight = height;
bmp_info.bmiHeader.biPlanes = 1;
bmp_info.bmiHeader.biBitCount = 24;
bmp_info.bmiHeader.biCompression = BI_RGB;
int bmp_padding = (width * 3) % 4;
if (bmp_padding != 0) bmp_padding = 4 - bmp_padding;
BYTE *bmp_pixels = new BYTE[(width * 3 + bmp_padding) * height];;
GetDIBits(hdc, hbmp, 0, height, bmp_pixels, &bmp_info, DIB_RGB_COLORS);
BITMAPFILEHEADER bmfHeader;
HANDLE bmp_file_handle = CreateFile("TestFile.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = (width * 3 + bmp_padding) * height + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader.bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM
DWORD dwBytesWritten = 0;
WriteFile(bmp_file_handle, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(bmp_file_handle, (LPSTR)&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(bmp_file_handle, (LPSTR)bmp_pixels, (width * 3 + bmp_padding) * height, &dwBytesWritten, NULL);
//Close the handle for the file that was created
CloseHandle(bmp_file_handle);
DeleteDC(hdc);
DeleteObject(hbmp);
ReleaseDC(NULL, hdcScreen);
delete[] bmp_pixels;
}
This can happen with many applications where the target window is simply a container and is not responsible for paint messages. Standard win32 applications like notepad don't behave as such. But you may run in to this problem with many browsers for example.
You can always take screenshot of desktop window. You can get the screen coordinate of target window, then bitblt
that section of target window. Make the following changes to your code:
//GetClientRect(handle, &client_rect);
GetWindowRect(handle, &client_rect);
//HDC hdcScreen = GetDC(handle);
HDC hdcScreen = GetDC(HWND_DESKTOP);
//BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY);
BitBlt(hdc, 0, 0, width, height, hdcScreen, client_rect.left, client_rect.top, SRCCOPY);
//ReleaseDC(NULL, hdcScreen);
ReleaseDC(HWND_DESKTOP, hdcScreen);
The target window must be top-most visible window on the screen before taking screen shot. For example you can call screenshot_window
in this order:
HWND hwnd = FindWindow(0, L"Calculator");
SetForegroundWindow(hwnd);
Sleep(1000);
screenshot_window(hwnd);
Alternatively, you can use Dwm Thumbnail APIs to paint the target window in your own window. But again, you cannot use GetDC(my_hWnd)
to access the bitmap from "Dwm Thumbnail" on your window. Again you would have to take screen shot of desktop window using GetDC(HWND_DESKTOP)
. This time make sure your own window is the top window.
Application must be DPI aware otherwise screen coordinates will not match.
Also there is a resource leak in the original code. GetDC
should be cleaned up with ReleaseDC
using the same handle
, not NULL
HDC hdcScreen = GetDC(handle);
...
//ReleaseDC(NULL, hdcScreen);
ReleaseDC(handle, hdcScreen);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With