C++ Windows下使用DXGI实现屏幕截图

1、包含必要的头文件:

#include <d3d11.h>
#include <dxgi1_2.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

2、创建一个函数来执行屏幕截图并过滤掉指定窗口:

void SaveScreenShot(ID3D11Device* pDevice, ID3D11DeviceContext* pImmediateContext, const char* filename)
{
    IDXGIDevice* pDXGIDevice = nullptr;
    pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&pDXGIDevice));

    IDXGIAdapter* pAdapter = nullptr;
    pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&pAdapter));

    IDXGIFactory1* pFactory = nullptr;
    pAdapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&pFactory));

    IDXGIOutput* pOutput = nullptr;
    pAdapter->EnumOutputs(0, &pOutput);

    IDXGIOutput1* pOutput1 = nullptr;
    pOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&pOutput1));

    IDXGIOutputDuplication* pOutputDuplication = nullptr;
    pOutput1->DuplicateOutput(pDevice, &pOutputDuplication);

    DXGI_OUTDUPL_DESC outputDuplicationDesc;
    pOutputDuplication->GetDesc(&outputDuplicationDesc);

    unsigned int bufferWidth = outputDuplicationDesc.ModeDesc.Width;
    unsigned int bufferHeight = outputDuplicationDesc.ModeDesc.Height;
    unsigned int bufferSize = bufferWidth * bufferHeight * 4;

    ID3D11Texture2D* pScreenTexture = nullptr;
    D3D11_TEXTURE2D_DESC texDesc;
    ZeroMemory(&texDesc, sizeof(texDesc));
    texDesc.Width = bufferWidth;
    texDesc.Height = bufferHeight;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 1;
    texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    texDesc.SampleDesc.Count = 1;
    texDesc.Usage = D3D11_USAGE_STAGING;
    texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

    pDevice->CreateTexture2D(&texDesc, NULL, &pScreenTexture);

    ID3D11Texture2D* pStagingTexture = nullptr;
    pDevice->CreateTexture2D(&texDesc, NULL, &pStagingTexture);

    DXGI_OUTDUPL_FRAME_INFO frameInfo;
    ID3D11Resource* pDesktopResource = nullptr;
    HRESULT hr = pOutputDuplication->AcquireNextFrame(500, &frameInfo, &pDesktopResource);
    if (hr == DXGI_ERROR_WAIT_TIMEOUT)
    {
        // 等待超时
    }
    else if (SUCCEEDED(hr))
    {
        pImmediateContext->CopyResource(pStagingTexture, pDesktopResource);
        pOutputDuplication->ReleaseFrame();

        pImmediateContext->CopyResource(pScreenTexture, pStagingTexture);

        D3D11_MAPPED_SUBRESOURCE mappedResource;
        pImmediateContext->Map(pScreenTexture, 0, D3D11_MAP_READ, 0, &mappedResource);

        unsigned char* pPixels = static_cast<unsigned char*>(mappedResource.pData);

        // 在这里保存屏幕截图为文件
        SaveBitmapToFile(pPixels, desc.Width, desc.Height, “c:/screenshot.bmp”)

        pImmediateContext->Unmap(pScreenTexture, 0);
    }

    pScreenTexture->Release();
    pStagingTexture->Release();
    pOutputDuplication->Release();
    pOutput1->Release();
    pOutput->Release();
    pFactory->Release();
    pAdapter->Release();
    pDXGIDevice->Release();
}

3、创建一个函数来保存位图到文件:

HRESULT SaveBitmapToFile(char* bmBits, int bmWidth, int bmHeight, const wchar_t* filePath)
{
    HRESULT result = S_OK;
 
    // 创建位图文件头
    BITMAPFILEHEADER fileHeader;
    fileHeader.bfType = 0x4D42;  // "BM"
    fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmWidthBytes * bmHeight;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
 
    // 创建位图信息头
    BITMAPINFOHEADER infoHeader;
    infoHeader.biSize = sizeof(BITMAPINFOHEADER);
    infoHeader.biWidth = bmWidth;
    infoHeader.biHeight = -bmHeight;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 32;
    infoHeader.biCompression = BI_RGB;
    infoHeader.biSizeImage = 0;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biClrImportant = 0;
 
    // 创建文件并写入位图数据
    HANDLE fileHandle = CreateFileW(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fileHandle != INVALID_HANDLE_VALUE)
    {
        DWORD bytesWritten = 0;
        WriteFile(fileHandle, &fileHeader, sizeof(BITMAPFILEHEADER), &bytesWritten, NULL);
        WriteFile(fileHandle, &infoHeader, sizeof(BITMAPINFOHEADER), &bytesWritten, NULL);
        WriteFile(fileHandle, bmBits, bmWidth * bmp.bmHeight * 4, &bytesWritten, NULL);
        CloseHandle(fileHandle);
    }
    else
    {
        result = E_FAIL;
    }
 
    return result;
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值