在 Windows 中截取屏幕截图会输出黑屏图像

问题描述 投票:0回答:2

我正在尝试在 Windows 中截取整页屏幕截图。函数在第一次调用中有效,但在第二次调用后根本不起作用,它只是获得尺寸稳定的黑屏图像。 当我使用调试器时,该功能运行良好,不会出现黑屏。

这是代码:

void screenshot(std::string imageaPath)
{
    ULONG_PTR gdiplustoken;
    Gdiplus::GdiplusStartupInput gdistartupinput;
    Gdiplus::GdiplusStartupOutput gdistartupoutput;

    gdistartupinput.SuppressBackgroundThread = true;
    GdiplusStartup(&gdiplustoken, &gdistartupinput, &gdistartupoutput); //start GDI+

    HDC hScreenDC = GetDC(GetDesktopWindow());
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

    int cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    int cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    int x = GetSystemMetrics(SM_XVIRTUALSCREEN); 
    int y = GetSystemMetrics(SM_YVIRTUALSCREEN);

    HBITMAP hbitmap = CreateCompatibleBitmap(hScreenDC, cx, cy);
    HBITMAP holdbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hbitmap));

    BitBlt(hMemoryDC, 0, 0, cx, cy, hScreenDC, x, y, SRCCOPY | CAPTUREBLT);
    hbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, holdbitmap));    

    UINT num, size;

    Gdiplus::ImageCodecInfo* imagecodecinfo;
    Gdiplus::GetImageEncodersSize(&num, &size); // get count of codec

    imagecodecinfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
    GetImageEncoders(num, size, imagecodecinfo);//get codec

    CLSID clsidEncoder;

    for (int i = 0; i < num; i++)
    {
        if (wcscmp(imagecodecinfo[i].MimeType, L"image/jpeg") == 0)
            clsidEncoder = imagecodecinfo[i].Clsid; // get jpeg codec id
    }

    free(imagecodecinfo);
    Gdiplus::Bitmap* bm = new Gdiplus::Bitmap(hbitmap, NULL);
    std::wstring ws;
    ws.assign(imageaPath.begin(), imageaPath.end());//sring to wstring
    bm->Save(ws.c_str(), &clsidEncoder); //save in jpeg format
    SelectObject(hMemoryDC, holdbitmap);//Release Objects
    DeleteObject(hMemoryDC);
    DeleteObject(hbitmap);
    ReleaseDC(GetDesktopWindow(), hScreenDC);

    Gdiplus::GdiplusShutdown(gdiplustoken);
}

更新:

好吧,我找到了一种方法来截取没有黑屏图像的屏幕截图 当我使用

system("pause");
使程序停止并按 Enter 键使程序继续时,它正在工作,我使用了 C++ 睡眠方法但不起作用,知道吗?

...
HBITMAP holdbitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hbitmap));

system("pause");

BitBlt(hMemoryDC, 0, 0, cx, cy, hScreenDC, x, y, SRCCOPY | CAPTUREBLT);
...

睡眠方法:

Sleep(1000);
std::this_thread::sleep_for(std::chrono::seconds(1));

更新2:

我正在使用curl发送屏幕截图请求,我正在服务器(rdp)中进行测试,当我发送请求时我被注销了,我认为服务器中的睡眠模式已启用,当我注销时服务器将处于睡眠状态,就像计算机屏幕变黑,这就是 BitBlt() 失败并且 GetLastError() 将返回 5 的原因,这意味着访问被拒绝

c++ winapi gdi+
2个回答
6
投票

GdiplusShutdown
的文档说

您必须在创建任何 GDI+ 对象之前调用

GdiplusStartup
,并且 您必须删除所有 GDI+ 对象(或让它们超出范围)在调用
GdiplusShutdown
之前。

您泄露了

bm = new Gdiplus::Bitmap(...)
,这违反了此规则。


0
投票

您可以使用 PrintWindow 来替代 BitBlt api,PrintWindow 的

nFlags
应设置为
PW_RENDERFULLCONTENT
,请确保您在 Windows 8.1 及更高版本的操作系统计算机上调用此函数,可能会起作用,请尝试一下。

© www.soinside.com 2019 - 2024. All rights reserved.