截取全屏幕

#include <windows.h>
 
void echo(CHAR *str);
int CaptureImage(HWND hWnd, CHAR *dirPath, CHAR *filename);
 
int main()
{
    echo(TEXT("Ready"));
    CaptureImage(GetDesktopWindow(), "E:\", "screen"); // 保存为 E:screen.bmp
    echo(TEXT("end"));
    return 0;
}
 
/**
 * 调试输出
 */
void echo(CHAR *str)
{
    MessageBox(NULL, str, NULL, MB_OK);
}
 
/**
 * GDI 截屏函数
 *
 * 参数 hwnd   要截屏的窗口句柄
 * 参数 dirPath    截图存放目录
 * 参数 filename 截图名称
 */
int CaptureImage(HWND hwnd, CHAR *dirPath, CHAR *filename)
{
    HANDLE hDIB;
    HANDLE hFile;
    DWORD dwBmpSize;
    DWORD dwSizeofDIB;
    DWORD dwBytesWritten;
    CHAR FilePath[MAX_PATH];
    HBITMAP hbmScreen = NULL;
    BITMAP bmpScreen;
    BITMAPFILEHEADER bmfHeader;
    BITMAPINFOHEADER bi;
    CHAR *lpbitmap;
    INT width = GetSystemMetrics(SM_CXSCREEN);  // 屏幕宽
    INT height = GetSystemMetrics(SM_CYSCREEN);  // 屏幕高
    HDC hdcScreen = GetDC(NULL); // 全屏幕DC
    HDC hdcMemDC = CreateCompatibleDC(hdcScreen); // 创建兼容内存DC
 
    if (!hdcMemDC)
    {
        echo(TEXT("CreateCompatibleDC has failed"));
        goto done;
    }
 
    // 通过窗口DC 创建一个兼容位图
    hbmScreen = CreateCompatibleBitmap(hdcScreen, width, height);
 
    if (!hbmScreen)
    {
        echo(TEXT("CreateCompatibleBitmap Failed"));
        goto done;
    }
 
    // 将位图块传送到我们兼容的内存DC中
    SelectObject(hdcMemDC, hbmScreen);
    if (!BitBlt(
                hdcMemDC,    // 目的DC
                0, 0,        // 目的DC的 x,y 坐标
                width, height, // 目的 DC 的宽高
                hdcScreen,   // 来源DC
                0, 0,        // 来源DC的 x,y 坐标
                SRCCOPY))    // 粘贴方式
    {
        echo(TEXT("BitBlt has failed"));
        goto done;
    }
 
    // 获取位图信息并存放在 bmpScreen 中
    GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
 
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bmpScreen.bmWidth;
    bi.biHeight = bmpScreen.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;
 
    dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
 
    // 在 32-bit Windows 系统上, GlobalAlloc 和 LocalAlloc 是由 HeapAlloc 封装来的
    // handle 指向进程默认的堆. 所以开销比 HeapAlloc 要大
    hDIB = GlobalAlloc(GHND, dwBmpSize);
    lpbitmap = (char *)GlobalLock(hDIB);
 
    // 获取兼容位图的位并且拷贝结果到一个 lpbitmap 中.
    GetDIBits(
        hdcScreen,  // 设备环境句柄
        hbmScreen,  // 位图句柄
        0,          // 指定检索的第一个扫描线
        (UINT)bmpScreen.bmHeight, // 指定检索的扫描线数
        lpbitmap,   // 指向用来检索位图数据的缓冲区的指针
        (BITMAPINFO *)&bi, // 该结构体保存位图的数据格式
        DIB_RGB_COLORS // 颜色表由红、绿、蓝(RGB)三个直接值构成
    );
 
 
    wsprintf(FilePath, "%s\%s.bmp", dirPath, filename);
 
    // 创建一个文件来保存文件截图
    hFile = CreateFile(
                FilePath,
                GENERIC_WRITE,
                0,
                NULL,
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                NULL
            );
 
    // 将 图片头(headers)的大小, 加上位图的大小来获得整个文件的大小
    dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
 
    // 设置 Offset 偏移至位图的位(bitmap bits)实际开始的地方
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
 
    // 文件大小
    bmfHeader.bfSize = dwSizeofDIB;
 
    // 位图的 bfType 必须是字符串 "BM"
    bmfHeader.bfType = 0x4D42; //BM
 
    dwBytesWritten = 0;
    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
 
    // 解锁堆内存并释放
    GlobalUnlock(hDIB);
    GlobalFree(hDIB);
 
    // 关闭文件句柄
    CloseHandle(hFile);
 
    // 清理资源
done:
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(NULL, hdcScreen);
 
    return 0;
}
/**
*其实这样截取出来的图片会过大,而且效率也不是很高,如果要改善这个情况的话,需要重新写一
*个拷贝函数,因为没有必要每一个颜色(bit)全都拷贝出来,过滤到很多再拷贝的话程序效率会更高,
*而且图片也会更小,唯一就是图片质量可能会下降。
*/
 
 

截取指定窗口

#include <windows.h>
 
void echo(CHAR *str);
int CaptureImage(HWND hWnd, CHAR *dirPath, CHAR *filename);
 
int main()
{
    echo("准备截图");
    CaptureImage(GetDesktopWindow(), "E:\", "hello"); // 保存为 E:hello.bmp
    echo("截图结束");
    return 0;
}
 
/**
 * 调试输出
 */
void echo(CHAR *str)
{
    MessageBox(NULL, str, NULL, MB_OK);
}
 
/**
 * GDI 截取指定窗口
 *
 * 参数 hwnd   要截屏的窗口句柄
 * 参数 dirPath    截图存放目录
 * 参数 filename 截图名称
 */
int CaptureImage(HWND hwnd, CHAR *dirPath, CHAR *filename)
{
    HDC mdc;
    HBITMAP hbmp;
    CHAR FilePath[MAX_PATH];
    HDC hdcScreen;
    HDC hdcWindow;
    HDC hdcMemDC = NULL;
    HBITMAP hbmScreen = NULL;
    BITMAP bmpScreen;
    RECT rcClient;
    BITMAPFILEHEADER   bmfHeader;   
    BITMAPINFOHEADER   bi;
    DWORD dwBmpSize;
    HANDLE hDIB;
    CHAR *lpbitmap;
    HANDLE hFile;
    DWORD dwSizeofDIB;
    DWORD dwBytesWritten;
 
    hdcScreen = GetDC(NULL); // 全屏幕DC
    hdcWindow = GetDC(hwnd); // 截图目标窗口DC
 
    // 创建兼容内存DC
    hdcMemDC = CreateCompatibleDC(hdcWindow);
 
    if(!hdcMemDC)
    {
        echo(TEXT("CreateCompatibleDC has failed"));
        goto done;
    }
 
    // 获取客户端区域用于计算大小
    GetClientRect(hwnd, &rcClient);
 
    // 设置延展模式
    SetStretchBltMode(hdcWindow, HALFTONE);
 
    // 来源 DC 是整个屏幕而目标 DC 是当前的窗口 (HWND)
    if(!StretchBlt(hdcWindow,
        0,0,
        rcClient.right, rcClient.bottom,
        hdcScreen,
        0,0,
        GetSystemMetrics (SM_CXSCREEN),
        GetSystemMetrics (SM_CYSCREEN),
        SRCCOPY))
    {
        echo(TEXT("StretchBlt has failed"));
        goto done;
    }
 
    // 通过窗口DC 创建一个兼容位图
    hbmScreen = CreateCompatibleBitmap(
        hdcWindow,
        rcClient.right-rcClient.left,
        rcClient.bottom-rcClient.top
        );
 
    if(!hbmScreen)
    {
        echo(TEXT("CreateCompatibleBitmap Failed"));
        goto done;
    }
 
    // 将位图块传送到我们兼容的内存DC中
    SelectObject(hdcMemDC,hbmScreen);
    if(!BitBlt(
        hdcMemDC,   // 目的DC
        0,0,        // 目的DC的 x,y 坐标
        rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, // 目的 DC 的宽高
        hdcWindow,  // 来源DC
        0,0,        // 来源DC的 x,y 坐标
        SRCCOPY))   // 粘贴方式
    {
        echo(TEXT("BitBlt has failed"));
        goto done;
    }
 
    // 获取位图信息并存放在 bmpScreen 中
    GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
 
    bi.biSize = sizeof(BITMAPINFOHEADER);   
    bi.biWidth = bmpScreen.bmWidth;   
    bi.biHeight = bmpScreen.bmHeight; 
    bi.biPlanes = 1;   
    bi.biBitCount = 32;   
    bi.biCompression = BI_RGB;   
    bi.biSizeImage = 0; 
    bi.biXPelsPerMeter = 0;   
    bi.biYPelsPerMeter = 0;   
    bi.biClrUsed = 0;   
    bi.biClrImportant = 0;
 
    dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
 
    // 在 32-bit Windows 系统上, GlobalAlloc 和 LocalAlloc 是由 HeapAlloc 封装来的
    // handle 指向进程默认的堆. 所以开销比 HeapAlloc 要大
    hDIB = GlobalAlloc(GHND,dwBmpSize);
    lpbitmap = (char *)GlobalLock(hDIB);   
 
    // 获取兼容位图的位并且拷贝结果到一个 lpbitmap 中.
    GetDIBits(
        hdcWindow,  // 设备环境句柄
        hbmScreen,  // 位图句柄
        0,          // 指定检索的第一个扫描线
        (UINT)bmpScreen.bmHeight, // 指定检索的扫描线数
        lpbitmap,   // 指向用来检索位图数据的缓冲区的指针
        (BITMAPINFO *)&bi, // 该结构体保存位图的数据格式
        DIB_RGB_COLORS // 颜色表由红、绿、蓝(RGB)三个直接值构成
        );
 
 
    wsprintf(FilePath, "%s\%s.bmp", dirPath, filename);
 
    // 创建一个文件来保存文件截图
    hFile = CreateFile(
        FilePath,
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
 
    // 将 图片头(headers)的大小, 加上位图的大小来获得整个文件的大小
    dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
 
    // 设置 Offset 偏移至位图的位(bitmap bits)实际开始的地方
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
 
    // 文件大小
    bmfHeader.bfSize = dwSizeofDIB;
 
    // 位图的 bfType 必须是字符串 "BM"
    bmfHeader.bfType = 0x4D42; //BM  
 
    dwBytesWritten = 0;
    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
 
    // 解锁堆内存并释放
    GlobalUnlock(hDIB);   
    GlobalFree(hDIB);
 
    // 关闭文件句柄
    CloseHandle(hFile);
 
    // 清理资源
done:
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(NULL,hdcScreen);
    ReleaseDC(hwnd,hdcWindow);
 
    return 0;
}

C语言 屏幕截图 (GDI)的更多相关文章

  1. 疯狂的图形(利用C# + GDI plus模拟杂乱无章的现实场景)

    原文:疯狂的图形(利用C# + GDI plus模拟杂乱无章的现实场景) 本文给出了模拟竹叶.长叶草.杂乱石头.天上繁星等关键代码.使用.Net环境下C#语言,GDI+编写.   模拟竹叶 挺像的吧? ...

  2. iOS - Harpy版本更新工具兼容版本第三方库

    Harpy(兼容版) git地址:https://github.com/yangchao0033/Harpy ###(iOS5-9适配版本,基于ArtSabintsev/Harpy v3.4.5) 提 ...

  3. 如何在GooglePlay上面发布应用

    上传和发布应用 注册开发者帐户后,您便可使用 Google Play 开发者控制台将应用上传到 Google Play. 访问 Google Play 开发者控制台. 点击屏幕顶部附近的添加新用户. ...

  4. C语言集锦(三)Direct3D和GDI+的例子

    0.前言 有些时候你可能想了解,如何用纯C语言来写Direct3D和GDI+的Demo.注意,下面的Direct3D例子不适用于TCC编译器,GDI+的例子是可以的. 1.Direct3D C语言的例 ...

  5. Windows GDI 窗口与 Direct3D 屏幕截图

    前言 Windows 上,屏幕截图一般是调用 win32 api 完成的,如果 C# 想实现截图功能,就需要封装相关 api.在 Windows 上,主要图形接口有 GDI 和 DirectX.GDI ...

  6. WinForm GDI+ 资料收集

    UI(User Interface)编程在整个项目开发过程中是个颇为重要的环节,任何好的解决方案若没有良好的用户界面呈现给最终用户,那么就算包含了最先进的技术也不能算是好程序.UI编程体现在两个方面, ...

  7. C# WinForm开发系列 - GDI+【转】

    http://blog.csdn.net/blue_sky6/article/details/53811435?locationNum=6&fps=1 C# WinForm开发系列 - GDI ...

  8. 使用Python保存屏幕截图(不使用PIL)

    起因 在极客学院讲授<使用Python编写远程控制程序>的课程中,涉及到查看被控制电脑屏幕截图的功能. 如果使用PIL,这个需求只需要三行代码: from PIL import Image ...

  9. 吉特仓库管理系统- 斑马打印机 ZPL语言的腐朽和神奇

    上一篇文章说到了.NET中的打印机,在PrintDocument类也暴露一些本质上上的问题,前面也提到过了,虽然使用PrintDcoument打印很方便.对应条码打印机比如斑马等切刀指令,不依赖打印机 ...

随机推荐

  1. 解决VS+Qt不生成moc文件问题

    使用VS的Qt插件进行Qt开发时,有时候会遇到不能生成moc文件的问题. 1.在工程中可以看到这个Generated files目录下是有一个看似moc文件的文件,双击打开的话: 如果能正常打开,文件 ...

  2. Inno Setup 设置开机启动

    案1: 将快捷方式添加到“启动”文件夹 [Tasks] Name: "startupicon"; Description: "{cm:CreateQuickLaunchI ...

  3. PHP如何输出合并单元格的表

    https://mp.weixin.qq.com/s/ChPIKIv9tqmuqGyfc9Zi7Q 合并单元格的表,很多地方可以见到,比如购物车,订单合并等,今天给大家讲解一下,如何操作,虽然我用的l ...

  4. Best Time to Sell and Buy Stock

    这道题想了很多,但是想多了.这个题思路很简单,如果当前值大于最小值,就计算差,和最大利润值比较. class Solution { public: int maxProfit(vector<in ...

  5. hdu1503 LCS

    题意:如果有相同的字母,这些字母只输出一次.其余的都输出. 先做一次LCS,标记相同的字母,然后回溯输出. #include<stdio.h> #include<string.h&g ...

  6. 阿里开源新一代 AI 算法模型,由达摩院90后科学家研发

    最炫的技术新知.最热门的大咖公开课.最有趣的开发者活动.最实用的工具干货,就在<开发者必读>! 每日集成开发者社区精品内容,你身边的技术资讯管家. 每日头条 阿里开源新一代 AI 算法模型 ...

  7. [React Native]高度自增长的TextInput组件

    之前我们学习了从零学React Native之11 TextInput了解了TextInput相关的属性. 在开发中,我们有时候有这样的需求, 希望输入区域的高度随着输入内容的长度而增长, 如下: 这 ...

  8. JSTL的时间格式化

    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> 开头第一句必须上 ...

  9. iOS打包上传ipa文件时,报错<ERROR ITMS-90096: "Your binary is not optimized for iPhone 5 - New iPhone apps......>的解决方案

    很长一段时间习惯了用企业级证书发布,最近的新项目使用Xcode 9.1发布到AppStore时遇到了一个小问题(emm..其实问题跟Xcode版本没关系,我也不知道为什么要声明这个233),如下: E ...

  10. HDOJ1016 Prime Ring Problem(DFS深层理解)

      Prime Ring Problem                                                                       时间限制: 200 ...