借助Nick Nougat的答案here中的代码,我可以使用BitBlt和GetDIBits成功捕获屏幕的一部分。
捕获整个屏幕或桌面似乎可以正常工作,但是当我提供应用程序的HDC时,它将打印奇怪的数据(以bgra格式)。
rect
...
event.target
表示电子应用支持HWND dekstopHWND = GetDesktopWindow();
// prints correct desktop pixels
HWND appHWND = FindWindowA(NULL, "Hello World!"); // working handle of an electron app
//prints 0 0 0 0 as pixels
HWND appHWND = FindWindowA(NULL, "Untitled - Notepad"); // Notepad app
//prints 255 255 255 0 as pixels
,并且
设备GetDeviceCaps
是BitBlt
。TECHNOLOGY
,是否正确?我对Windows API还是很陌生... steps或函数中的哪一个可能导致此问题? 谢谢。
....
raster display
答案 0 :(得分:1)
GetDC
仅可用于在本地Win32应用程序中拍摄客户区的屏幕快照。包括记事本之类的程序。或者,您可以使用GetWindowDC
截取整个窗口的屏幕截图。
但是,用电子应用程序,QT,WPF等框架制作的应用程序将响应GetDC
或GetWindowDC
打印黑屏。唯一的解决方法是确保目标应用程序可见,并在目标应用程序所在的特定坐标处为桌面截图。
Windows GDI函数通常忽略Alpha通道。但是,如果您以32位检索屏幕快照,那么GetDIBits
会将所有alpha值设置为255(至少在Windows 10中)。
您的代码存在资源泄漏,因为它使用错误的窗口句柄调用ReleaseDC
。如果您呼叫GetDC(NULL)
,则以ReleaseDC(NULL, hdc)
结尾,否则应按以下说明更正它:
HDC hdc = GetDC(appHWND);
...
//ReleaseDC(NULL, hdc); <- wrong window handle
ReleaseDC(appHWND, hdc);
您也可以保存整个图像,而不是一次打印一个字节。示例:
#include <fstream>
#include <vector>
#include <windows.h>
int main()
{
//make sure process is DPI aware
SetProcessDPIAware();
HWND hwnd_target = FindWindowA("Notepad", NULL);
if(!hwnd_target)
return 0;
//make sure target window is on top
SetForegroundWindow(hwnd_target);
Sleep(250);
//get hdc of desktop
HDC hdc = GetDC(HWND_DESKTOP);
//copy bits from coordinates of target window
RECT rc;
GetWindowRect(hwnd_target, &rc);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, w, h);
HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, w, h, hdc, rc.left, rc.top, SRCCOPY | CAPTUREBLT);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
//restore the foreground
SetForegroundWindow(GetConsoleWindow());
//save to file
BITMAPINFOHEADER bi = { sizeof(bi), w, h, 1, 32 };
std::vector<BYTE> pixels(w * h * 4);
GetDIBits(hdc, hbitmap, 0, h, pixels.data(),
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
std::ofstream fout("filename.bmp", std::ios::binary);
BITMAPFILEHEADER hdr = { 'MB', 54 + bi.biSizeImage, 0, 0, 54 };
fout.write((char*)&hdr, 14);
fout.write((char*)&bi, 40);
fout.write((char*)pixels.data(), pixels.size());
DeleteObject(hbitmap);
ReleaseDC(HWND_DESKTOP, hdc);
return 0;
}