首页 > 编程语言 >C++使用Win32GDI DC进行屏幕截图

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

时间:2024-09-20 10:36:01浏览次数:11  
标签:NULL Win32GDI bfh bi C++ DC bmp sizeof include

代码

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

标签:NULL,Win32GDI,bfh,bi,C++,DC,bmp,sizeof,include
From: https://www.cnblogs.com/PeterZ1997/p/18421988

相关文章

  • 【C++】C++ STL探索:Priority Queue与仿函数的深入解析
    C++语法相关知识点可以通过点击以下链接进行学习一起加油!命名空间缺省参数与函数重载C++相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C++内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与Queue这篇文......
  • C++ std::find函数 容器元素查找
    简介std::find函数是C++标准库内非常实用的一个函数,主要用于在给定范围内查找某个元素,如果找到该元素,则返回指向该元素的迭代器;如果没有找到,则返回指向范围末尾的迭代器(即 end() )。find函数原型std::find在头文件algorithm中template<classInputIt,classT>Inp......
  • C++ | 引用详解
    文章目录C++引用详解一、什么是引用二、引用的语法三、引用的特点1.必须初始化2.与原始对象具有相同的内存地址3.没有独立的存储空间4.传递参数高效四、引用的用途1.函数参数传递2.返回值3.用于实现运算符重载五、引用与指针的区别1.语法2.初始化3.空值4.操......
  • C++标准的一些特性记录:C++11的thread_local
    文章目录thread_localthread_local在多线程的编程环境里,一般来说,所有的线程都是共享同一个内存空间,也就是说如果定义一个变量,这个变量是被所有线程共享的,所以多个变量在访问同一个变量时,是需要加锁机制的,否则就会出现问题。在C++11中,引入了一个关键字thread_local......
  • C++代码编译过程
    代码转换成可执行文件的全过程看了一些网上的文章,觉的还是自己写写看看才能理解通透,也为找简历做准备。代码转换成可执行文件分为4个步骤,预处理、编译、汇编、链接。预处理这个过程是执行代码中的一些预处理指令,多说无益,直接上代码#include<iostream>#defineBesttrue;#i......
  • 蓝桥杯十五届软件赛C++B组题解
    最近蓝桥杯官网已经把十五届题目上架了,我会尽快的将题解发出来,没有发的过段时间再补。​​​​​​​数字接龙一个很鹅心的搜索题,一不注意就会写错,比赛的时候写不来,题目上架后也WA了两个样例才过。题目大意:也就是说从(1,1)开始 ,下一步路的数据总是要比当前数据大1,超过k就......
  • C++内存管理
    前言接下来我们继续学习C++的内存管理。1. C++/C中程序内存区域划分C++将内存区域划分为四个部分,分别是栈区,堆区,静态区,常量区。其中静态区又叫数据段,其中存储全局数据和动态数据。常量区又叫代码区,其中存储只读常量和可执行代码。栈里面存储函数参数,返回值,局部变量等。......
  • C++笔记21•C++11的新特性•
       相比于 C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而......
  • C++入门基础知识76(实例)——实例 1【输出 “Hello, World!“】
    成长路上不孤单......
  • C++刷怪笼(6)模板初阶
    1.前言在学习C++模板之前,我们会被同种函数的不同数据类型的繁琐写法而折磨,今天我们进入对模板的学习,来进一步的感受C++为我们今后的编程学习和工作所带来的便利。2.模板2.1泛型编程我们应该如何去实现一个所有数据类型通用的函数?voidSwap(int&left,int&right){i......