c++ 捕获最小化窗口的屏幕截图

gtlvzcf8  于 2023-03-05  发布在  其他
关注(0)|答案(1)|浏览(308)

我试着按照这个例子发现:Capturing an image from a minimized window
我的代码:

#include <iostream>
#include <string>
#include <windows.h>
#include <gdiplus.h>

#pragma comment(lib, "gdiplus.lib")
#pragma warning(disable : 4996)

using namespace std;
using namespace Gdiplus;

int GetEncoderClsid(LPCWSTR format, CLSID* pClsid)
{
    unsigned int num = 0, size = 0;
    GetImageEncodersSize(&num, &size);
    if (size == 0) return -1;
    ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL) return -1;
    GetImageEncoders(num, size, pImageCodecInfo);

    for (unsigned int j = 0; j < num; ++j) {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }
    free(pImageCodecInfo);
    return -1;
}

int SaveScreenshot(string filename, ULONG uQuality, HWND hwnd) // by Napalm
{
    ULONG_PTR gdiplusToken;
    GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    HWND hMyWnd = hwnd;
    //HWND hMyWnd = GetDesktopWindow();

    RECT r;
    int w, h;
    HDC dc, hdcCapture;
    int nBPP, nCapture, iRes;
    LPBYTE lpCapture;
    CLSID imageCLSID;
    Bitmap* pScreenShot;

    // get the area of my application's window    
    GetWindowRect(hMyWnd, &r);
    dc = GetWindowDC(hMyWnd);   // GetDC(hMyWnd) ;
    w = r.right - r.left;
    h = r.bottom - r.top;
    nBPP = GetDeviceCaps(dc, BITSPIXEL);
    hdcCapture = CreateCompatibleDC(dc);

    // create the buffer for the screenshot
    BITMAPINFO bmiCapture = { sizeof(BITMAPINFOHEADER), w, -h, 1, nBPP, BI_RGB, 0, 0, 0, 0, 0, };

    // create a container and take the screenshot
    HBITMAP hbmCapture = CreateDIBSection(dc, &bmiCapture, DIB_PAL_COLORS, (LPVOID*)&lpCapture, NULL, 0);

    // failed to take it
    if (!hbmCapture) {
        DeleteDC(hdcCapture);
        DeleteDC(dc);
        GdiplusShutdown(gdiplusToken);
        printf("failed to take the screenshot. err: %d\n", GetLastError());
        return 0;
    }

    // copy the screenshot buffer
    nCapture = SaveDC(hdcCapture);
    SelectObject(hdcCapture, hbmCapture);
    BitBlt(hdcCapture, 0, 0, w, h, dc, 0, 0, SRCCOPY);
    RestoreDC(hdcCapture, nCapture);
    DeleteDC(hdcCapture);
    DeleteDC(dc);

    // save the buffer to a file  
    pScreenShot = new Bitmap(hbmCapture, (HPALETTE)NULL);
    EncoderParameters encoderParams;
    encoderParams.Count = 1;
    encoderParams.Parameter[0].NumberOfValues = 1;
    encoderParams.Parameter[0].Guid = EncoderQuality;
    encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
    encoderParams.Parameter[0].Value = &uQuality;
    GetEncoderClsid(L"image/jpeg", &imageCLSID);

    wchar_t* lpszFilename = new wchar_t[filename.length() + 1];
    mbstowcs(lpszFilename, filename.c_str(), filename.length() + 1);

    iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok);
    delete pScreenShot;
    DeleteObject(hbmCapture);
    GdiplusShutdown(gdiplusToken);
    return iRes;
}

int main() {
    HWND hWnd;
    hWnd = FindWindowA(NULL, "txt.txt - Bloco de Notas");

    WINDOWPLACEMENT wp = { 0 };
    wp.length = sizeof(WINDOWPLACEMENT);
    GetWindowPlacement(hWnd, &wp);

    ANIMATIONINFO ai = { 0 };
    bool restoreAnimated = false;

    if (wp.showCmd == SW_SHOWMINIMIZED)
    {
        ai.cbSize = sizeof(ANIMATIONINFO);
        SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);

        if (ai.iMinAnimate != 0)
        {
            ai.iMinAnimate = 0;
            SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
            restoreAnimated = true;
        }

        // optionally move the window off-screen, or
        // apply alpha using SetLayeredWindowAttributes()...

        ShowWindow(hWnd, SW_SHOWNOACTIVATE);
    }
    
    // capture as needed ...
    string path = "C:\\Users\\CAIO\\Desktop\\screenshot.jpg";
    ULONG quality = 100;
    SaveScreenshot(path, quality, hWnd);

    if (wp.showCmd == SW_SHOWMINIMIZED)
    {
        SetWindowPlacement(hWnd, &wp);

        // optionally remove alpha using SetLayeredWindowAttributes()...

        if (restoreAnimated)
        {
            ai.iMinAnimate = 1;
            SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
        }
    }

    return 0;
}

在他们的代码中有restoreAnimation = true;if (restoreAnimation),他们的意思是restoreAnimated吗?
使用上面的代码,它仍然显示窗口一秒钟,而且捕获的图像是全黑的(可能是在最小化时捕获的)或没有正确捕获。
https://youtu.be/8b1wXxtaXsY?t=9从视频的第8秒和第9秒,可以看到窗口显示在屏幕上。

hc2pp10m

hc2pp10m1#

他们的意思是恢复动画吗
我想是的。
This code from@Remy只在最小化和恢复时禁用动画效果,恢复时窗口仍然会显示很短的时间,正如答案所指出的,可以使用SetLayeredWindowAttributes使窗口几乎完全透明(需要注意的是,使用SetLayeredWindowAttributes需要确保hwnd具有WS_EX_LAYERED样式。)然后您将不会看到窗口,但操作系统会。
此外,窗口捕获不完整的问题是因为窗口没有完全绘制,在ShowWindow为我工作后调用UpdateWindow,它会向窗口发送一个WM_PAINT消息。

bool restoreAnimated = false;
BYTE Alph = 0;
LONG_PTR exstyle = 0;
if (wp.showCmd == SW_SHOWMINIMIZED)
{
    ai.cbSize = sizeof(ANIMATIONINFO);
    SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);

    if (ai.iMinAnimate != 0)
    {
        ai.iMinAnimate = 0;
        SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
        restoreAnimated = true;
    }

    // optionally move the window off-screen, or
    // apply alpha using SetLayeredWindowAttributes()...
    exstyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
    SetWindowLongPtr(hWnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
    DWORD flag;
    BOOL ret = GetLayeredWindowAttributes(hWnd, 0, &Alph, 0);
    SetLayeredWindowAttributes(hWnd, 0, 1, LWA_ALPHA);

    ShowWindow(hWnd, SW_SHOWNOACTIVATE);
    UpdateWindow(hWnd);
}

// capture as needed ...
string path = "C:\\Users\\name\\Desktop\\screenshot.jpg";
ULONG quality = 100;
SaveScreenshot(path, quality, hWnd);

if (wp.showCmd == SW_SHOWMINIMIZED)
{
    SetWindowPlacement(hWnd, &wp);

    // optionally remove alpha using SetLayeredWindowAttributes()...
    SetLayeredWindowAttributes(hWnd, 0, Alph, LWA_ALPHA);
    SetWindowLongPtr(hWnd, GWL_EXSTYLE, exstyle);

    if (restoreAnimated)
    {
        ai.iMinAnimate = 1;
        SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
    }
    
}

相关问题