BitBlt-使用其他应用程序的HDC时,捕获的像素全为零(bgra)

时间:2018-11-19 17:04:23

标签: windows winapi

借助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 ,并且 设备GetDeviceCapsBitBlt
  • 应用程序DC的宽度始终是全屏的,与窗口大小无关:TECHNOLOGY,是否正确?

我对Windows API还是很陌生... steps或函数中的哪一个可能导致此问题? 谢谢。

....

raster display

1 个答案:

答案 0 :(得分:1)

GetDC仅可用于在本地Win32应用程序中拍摄客户区的屏幕快照。包括记事本之类的程序。或者,您可以使用GetWindowDC截取整个窗口的屏幕截图。

但是,用电子应用程序,QT,WPF等框架制作的应用程序将响应GetDCGetWindowDC打印黑屏。唯一的解决方法是确保目标应用程序可见,并在目标应用程序所在的特定坐标处为桌面截图。

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;
}