C++使用Win32GDI DC进行屏幕截图

代码

#include <windows.h>
#include <Psapi.h>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <dxgi.h>
#include <d3d11.h>
#include <wrl.h>

BOOL SaveBitmapToFile(HBITMAP hBitmap, LPCTSTR filename)
{
    BITMAP bmp;
    GetObject(hBitmap, sizeof(BITMAP), &bmp);

    DWORD dwBmpSize = ((bmp.bmWidth * bmp.bmBitsPixel + 31) / 32) * 4 * bmp.bmHeight;

    HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
    char *lpbitmap = (char *)GlobalLock(hDIB);

    BITMAPINFOHEADER bi;
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bmp.bmWidth;
    bi.biHeight = bmp.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 24;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrImportant = 0;
    bi.biClrUsed = 0;

    // 获取位图数据
    GetDIBits(GetDC(NULL), hBitmap, 0, (UINT)bmp.bmHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);

    // 创建文件并写入数据
    HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwWritten;
    BITMAPFILEHEADER bfh;
    bfh.bfType = 0x4D42; // BM
    bfh.bfSize = sizeof(BITMAPFILEHEADER) + dwBmpSize;
    bfh.bfReserved1 = 0;
    bfh.bfReserved2 = 0;
    bfh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

    WriteFile(hf, (LPSTR)&bfh, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
    WriteFile(hf, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
    WriteFile(hf, lpbitmap, dwBmpSize, &dwWritten, NULL);

    // 清理
    GlobalUnlock(hDIB);
    GlobalFree(hDIB);
    CloseHandle(hf);

    return TRUE;
}

bool CaptureScreen(const wchar_t *filePath)
{
    // 获取屏幕宽高
    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);

    // 创建屏幕DC
    HDC hScreenDC = GetDC(NULL);
    if (!hScreenDC)
    {
        std::cerr << "Failed to get screen DC" << std::endl;
        return 1;
    }

    // 创建一个与屏幕DC兼容的内存DC
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
    if (!hMemoryDC)
    {
        std::cerr << "Failed to create memory DC" << std::endl;
        ReleaseDC(NULL, hScreenDC);
        return 1;
    }

    // 创建一个与屏幕兼容的位图
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
    if (!hBitmap)
    {
        std::cerr << "Failed to create bitmap" << std::endl;
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        return 1;
    }

    // 将位图选入内存DC
    HGDIOBJ old_obj = SelectObject(hMemoryDC, hBitmap);

    // 捕获屏幕到内存DC
    if (!BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY))
    {
        std::cerr << "Failed to capture screen" << std::endl;
        SelectObject(hMemoryDC, old_obj);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        return 1;
    }

    // 保存位图
    if (!SaveBitmapToFile(hBitmap, filePath))
    {
        std::cerr << "Failed to save bitmap" << std::endl;
    }

    // 清理资源
    SelectObject(hMemoryDC, old_obj);
    DeleteObject(hBitmap);
    DeleteDC(hMemoryDC);
    ReleaseDC(NULL, hScreenDC);

    return 0;
}

int main(void)
{
    CaptureScreen(L"E:\\output.bmp");
    return 0;
}

posted @ 2024-09-20 10:36  倚剑问天  阅读(147)  评论(0编辑  收藏  举报