简体   繁体   English

PrintWindow和隐藏窗口的BitBlt

[英]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() ? 我需要打电话给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? BitBlt()之前调用UpdateWindow() BitBlt()会有所不同吗? 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)? 我是否正确地假设对于PrintWindow()所有工作都是从目标应用程序内完成的(增加目标应用程序的CPU使用率),而BitBlt()是从调用线程内完全执行的(因此增加了我自己的CPU使用率)应用)?
  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). 我知道BitBlt()仅适用于隐藏窗口,如果启用了桌面合成(DWM),但是在一BitBlt()系统(Windows 8/10)上, BitBlt()PrintWindow()似乎对于它们工作的窗口失败在其他系统上就好了(即使启用了DWM)。 I could not spot any patterns as to why, though. 但是我无法发现任何关于原因的模式。

Any information is appreciated, thanks. 任何信息都表示赞赏,谢谢。

finally, after some hours of investigation, I found a solution for that issue: It's sufficient to call the following command within the ACTIVATE event of the form to be imaged (example in VB coding): 最后,经过几个小时的调查,我找到了解决该问题的方法:在要成像的表单的ACTIVATE事件中调用以下命令就足够了(例如在VB编码中):

Call SetWindowLong(me.hwnd, GWL_EXSTYLE, WS_EX_LAYERED)

Whereas this command is defined as follows: 而此命令定义如下:

Private Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Const GWL_EXSTYLE = (-20)

Private Const WS_EX_LAYERED = &H80000

Please try this! 请试试这个!

Best regards, Bambi66 此致,Bambi66

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. 两个多月后,我终于意识到这只发生在2018年末的Windows更新1809之后。显然,Windows改变了它使用该更新处理剪辑的方式,以便不再更新设备上下文内容的部分窗口屏幕外。

To answer the individual questions: 回答个别问题:

1) GdiFlush doesn't seem to make a difference, at least from what I can tell so far. 1)GdiFlush似乎没有什么区别,至少从目前为止我所知道的情况来看。

2) Still not 100% sure about it, but I also think it doesn't make a difference. 2)仍然不是100%肯定它,但我也认为它没有任何区别。

3) Still no idea. 3)仍然不知道。

4) See answer above. 4)见上面的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM