Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

c++ - PrintWindow and BitBlt of hidden windows

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:

  1. 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.
  2. Does the call to UpdateWindow() right before the BitBlt() make a difference? Does this help, so that the Device Context contents are "more up to date"?
  3. 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), while BitBlt() is fully executed from within the calling thread (thus increasing the CPU usage of my own application)?
  4. 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() and PrintWindow() 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After more than two months I finally realized that this only occurs with the Windows update 1809 from late 2018. Apparently, Windows changed the way it handles clipping with that update so that the Device Context contents are no longer updated for parts of windows that are located offscreen.

To answer the individual questions:

1) GdiFlush doesn't seem to make a difference, at least from what I can tell so far.

2) Still not 100% sure about it, but I also think it doesn't make a difference.

3) Still no idea.

4) See answer above.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...