My program is taking screenshots of other application windows to automate some tasks on them. Those windows can be hidden offscreen or obscured by other windows from time to time.
To reduce clutter, I have removed any error checking from the code listings. I am preparing the both types of screenshots with
// Get size of the target window.
RECT clientRect;
GetClientRect(hwnd, &clientRect);
int width = clientRect.right - clientRect.left;
int height = clientRect.bottom - clientRect.top;
// Create a memory device context.
HDC windowDC = GetDC(hwnd);
HDC memoryDC = CreateCompatibleDC(windowDC);
// Create a bitmap for rendering.
BITMAPINFO bitmapInfo;
ZeroMemory(&bitmapInfo, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = width;
bitmapInfo.bmiHeader.biHeight = -height;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = width * height * 4;
RGBQUAD* buffer;
HBITMAP bitmap = CreateDIBSection(windowDC, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, 0, 0);
HGDIOBJ previousObject = SelectOBject(memoryDC, bitmap);
then I am taking the actual screenshots with either
PrintWindow(hwnd, memoryDC, PW_CLIENTONLY);
GdiFlush();
or
UpdateWindow(hwnd);
BitBlt(memoryDC, 0, 0, width, height, windowDC, 0, 0, SRCCOPY);
GdiFlush();
then I copy the buffer contents to a vector
std::vector<RGBQUAD> pixels;
pixels.resize(width * height, { 0, 0, 0, 0 });
memcpy(&pixels[0], buffer, bitmapInfo.bmiHeader.biSizeImage);
and finally I am cleaning everything up with
ReleaseDC(hwnd, windowDC);
SelectObject(memoryDC, previousObject);
DeleteDC(memoryDC);
DeleteObject(bitmap);
I have a three of questions about the code above:
- Do I need to call
GdiFlush()
? I read the documentation and did some Google research, but I am still not sure if it makes sense to call it or not. - Does the call to
UpdateWindow()
right before theBitBlt()
make a difference? Does this help, so that the Device Context contents are "more up to date"? - Am I right in assuming that for
PrintWindow()
all the work is done from within the target application (increasing the target application's CPU usage), whileBitBlt()
is fully executed from within the calling thread (thus increasing the CPU usage of my own application)? - Under which circumstances might any of the above functions fail? I know that
BitBlt()
only works for hidden windows if Desktop Composition (DWM) is enabled, but on a very small set of systems (Windows 8/10)BitBlt()
andPrintWindow()
seem to fail for windows for which they work just fine on other systems (even though DWM is enabled). I could not spot any patterns as to why, though.
Any information is appreciated, thanks.
BitBlt
is a GDI call. OpenGL doesn't use GDI. Neither does DirectX. – Karlenekarlens