隐藏窗口的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();
或
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);
最后我要清理所有东西
ReleaseDC(hwnd, windowDC);
SelectObject(memoryDC, previousObject);
DeleteDC(memoryDC);
DeleteObject(bitmap);
关于上述代码,我有三个问题:
I have a three of questions about the code above:
- 我需要打
GdiFlush()
吗?我阅读了文档并进行了一些Google研究,但仍不确定是否可以调用它. - 在
BitBlt()
之前对UpdateWindow()
的调用会有所不同吗?这是否有帮助,以使设备上下文"的内容更及时"? - 我正确地认为,对于
PrintWindow()
,所有工作都在目标应用程序内完成(增加了目标应用程序的CPU使用率),而BitBlt()
在调用线程内完全执行了(因此增加了CPU使用率)我自己的应用程序)? - 在哪种情况下上述任何功能可能会失败?我知道
BitBlt()
仅在启用桌面合成(DWM)的情况下才适用于隐藏的窗口,但是在极少数系统(Windows 8/10)上,BitBlt()
和PrintWindow()
似乎对于适用于它们的窗口失败在其他系统上也没问题(即使启用了DWM).不过,我无法发现任何原因.
- 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.
感谢您提供任何信息.
推荐答案
最后,经过几个小时的调查,我找到了解决该问题的方法: 在要成像的表单的ACTIVATE事件中调用以下命令就足够了(以VB编码为例):
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):
Call SetWindowLong(me.hwnd, GWL_EXSTYLE, WS_EX_LAYERED)
此命令的定义如下:
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
请尝试这个!
最诚挚的问候, Bambi66
Best regards, Bambi66
这篇关于隐藏窗口的PrintWindow和BitBlt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!