获取图标的位图数据

  • 分两次使用GetDIBits(),以便于正确设置缓存的大小
  • 正确设置BITMAPINFO的大小,否则就会报堆栈溢出错误
ICONINFO info = { 0 };
GetIconInfo(hIcon, &info) HDC bmp, maskbmp; bmp = CreateCompatibleDC(NULL);
SelectObject(bmp, info.hbmColor); maskbmp = CreateCompatibleDC(NULL);
SelectObject(maskbmp, info.hbmMask); BYTE* lpvBits = NULL;
int nRet = 2; // 正确设置 BITMAPINFO 的大小,否则读取位图后头信息将无法存储
BITMAPINFO bmpInfo = { 0 };
bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
BITMAP bm;
GetObject(info.hbmMask, sizeof(bm), &bm);
int ncolors = 1 << bm.bmBitsPixel;
int bmpinfo_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ncolors;
std::vector<BYTE> buf(bmpinfo_size);
BITMAPINFO* bmpinfo = (BITMAPINFO*)buf.data();
bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 第一次调用,获取位图数据需要的多大的缓冲区存储
nRet = ::GetDIBits(maskbmp, info.hbmMask, 0, 0, NULL, bmpinfo, DIB_RGB_COLORS); // 设置正确的缓冲区存储位图数据
lpvBits = new BYTE[bmpinfo->bmiHeader.biSizeImage]; // 第二次调用,将位图数据存入缓冲区中
nRet = ::GetDIBits(maskbmp, info.hbmMask, 0, nHeight, lpvBits, bmpinfo, DIB_RGB_COLORS); // 按照每行有32列的形式打印,注意bmp位图数据是倒向的,打印出来的图像是实际图像的逆向
for (int i = 0; i < bmpinfo->bmiHeader.biSizeImage; i++)
{
if (i % 4 == 0) {
printf_s("\n");
}
BYTE tmp = lpvBits[i];
for (int j = 0; j < 8; j++)
{
bool res = tmp & 0x80;
tmp = tmp << 1;
printf_s("%d", res);
}
}
printf_s("\n");

使用注意

BITMAPINFOHEADER 结构后跟调色板条目或颜色掩码数组。 规则取决于 biCompression 的值。Link

  • 如果 biCompression 等于 BI_RGB并且 位图使用 8 bpp 或更少,则位图在 BITMAPINFOHEADER 结构之后立即具有颜色表。 颜色表由 RGBQUAD 值数组组成。 数组的大小由 biClrUsed 成员提供。 如果 biClrUsed 为零,则数组包含给定 bitdepth 的最大颜色数;即 2^biBitCount 颜色。
  • 如果 biCompression 是视频 FOURCC,则视频格式隐含颜色表的存在。 不应假定位深度为 8 bpp 或更少时存在颜色表。 但是,某些旧组件可能假定存在颜色表。 因此,如果要分配 BITMAPINFOHEADER 结构,建议在位深度为 8 bpp 或更少时为颜色表分配空间,即使不使用颜色表也是如此。
  • 请注意,如果位图使用颜色表或颜色掩码,则整个格式结构的大小 (BITMAPINFOHEADER 加上颜色信息) 不等于 sizeof(BITMAPINFOHEADER) 或 sizeof(BITMAPINFO)。 必须计算每个实例的实际大小。

根据Windows API官方介绍文档可以看出,使用GetDIBits()必须为BITMAPINFO计算实际的大小,否则从内存读取了较多内容,但是没有足够的空间去存放,在释放内存时就会出错,如堆栈错误或堆错误;当大于8bpp时,颜色表占用的内存空间剧增,机器内存很可能无法满足,因此不再建议使用此函数。

使用GetDIBits()获取Windows位图数据的标准用法,解决内存、堆栈报错问题的更多相关文章

  1. 关于jsp web项目,jsp页面与servlet数据不同步的解决办法(报错404、405等)即访问.jsp和访问web.xml中注册的/servlet/的区别

    报错信息: Type Status Report Message HTTP method GET is not supported by this URL Description The method ...

  2. windows下配置redis集群,启动节点报错:createing server TCP listening socket *:7000:listen:Unknown error

    windows下配置redis集群,启动节点报错:createing server TCP listening socket *:7000:listen:Unknown error 学习了:https ...

  3. Windows Server 2012 R2 安装.NET Framework 3.5报错

    简单记录一下,Windows Server 2012 R2 安装.NET Framework 3.5报错,下面是解决方法 载入ISO文件Windows Server 2012 R2,而且在安装的过程中 ...

  4. 【问题记录】使用FreeMarker生成数据,模板明明没错却一直报错“The following has evaluated to null or missing:”

    今天使用FreeMarker生成数据时一直报错,错误信息是“The following has evaluated to null or missing:”,告知我找不到值. 但是我再三确认,这些属性 ...

  5. Servlet(三):获取表单数据、解决乱码和报错问题

    在了解了servlet的生命周期以及运行过程后,再来动手写一个小例子,加深对servlet的理解. 一.需求说明 在用户注册信息页面,输入用户名.密码.性别.邮箱等一些信息后,页面返回刚刚填写的信息. ...

  6. 解决asp.net 报错 无法获取所需的权限错误

    asp.net 报错 无法获取所需的权限 无法获取所需的权限.说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 无法获取所 ...

  7. Python2.7在Windows下CMD编码为65001/utf-8时print报错[Errno 0]/[Errno 2]

    使用python2.7处理unicode的字符串,环境变量已设置PYTHONIOENCODING为utf-8,cmd编码为utf-8时print unicode字符串会报错[Errno 0]或[Err ...

  8. 解决kettle在两个mysql之间迁移数据时乱码的问题 和 相关报错 及参数调整, 速度优化

    1. 乱码问题 编辑目标数据库的链接: 配置编码参数即可. 2. 报错 No operations allowed after statement closed. 需要调整wait_timeout:  ...

  9. Windows安装Redis并添加本地自启动服务并解决客户端dll报错

    参考文章:https://blog.csdn.net/realjh/article/details/82026160 Redis下载: https://github.com/MicrosoftArch ...

  10. [vue]子组件通过props获取父组件数据以及使用watch解决动态数据不生效问题

    父子组件的传值,在Vue官方也写得很清楚,父组件中使用v-bind绑定传送,子组件使用props接收. 父组件通过v-bind绑定数据: <template> <router-vie ...

随机推荐

  1. 5.django-模型ORM

    Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库的操作,通过定义模型类来完成对数据库中表的操作 O:Object,也就是类对象的意思 R:Relation,关系数据库中表的意思 M: ...

  2. xshell取消置顶

    现象:xshell置顶,导致无法正常浏览其他应用,文件等 原因分析:打开xshell时,触发其置顶快捷方式:Alt+A 解决建议:针对此问题,首先,可以从"查看栏"手动取消置顶:其 ...

  3. SerialException:Cannot configure port something went wrong

    完整报错 SerialException:Cannot configure port something went wrong, Original message: OSError(22, '参数错误 ...

  4. 关于在linux上vm virtualbox读取不到U盘问题的解决

    1.设置usb2.0模式 如果你没安装拓展插件的话,调成usb2.0就会出现无效的配置这个提示,并且启动虚拟机会报 Implementation of the USB 2.0 controller n ...

  5. DHorse操作手册

    在介绍DHorse的操作之前,我们先来看一下发布一个系统的流程是什么样的. 发布系统的流程 我们以一个Springboot系统为例,来说明一下发布流程. 1.首先从代码仓库下载代码,比如Gitlab: ...

  6. vulnhub靶场渗透实战11-Deathnote

    ​网络模式,怎么方便怎么来. 靶场地址:https://download.vulnhub.com/deathnote/Deathnote.ova 这个靶机很简单.vbox装好.​ 1:主机发现,和端口 ...

  7. 文件服务器 — File Browser

    前言 一直想部署一套文件服务器,供队友之间相互传输文件.平时用微信发送文件真的太烦了,每发送或者接收一次都会有一个新的文件,造成重复文件太多了.文件服务器统一管理,自己需要什么文件再下载. 前面也安装 ...

  8. RocketMQ 在网易云音乐的实践

    本文作者:蒋星韬,网易云音乐服务端开发工程师. 云音乐线上场景众多,比如直播.评论.广告,各个业务线都会有消息场景比如发奖券,也会有延迟消息和事务消息场景,以及大数据做埋点数据.数据清洗.离线处理等. ...

  9. linux开机自启动设置

    方法一:修改 /etc/rc.d/rc.local 文件/etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行.所以想要脚本在开机后被运行的话,可以将自己脚本路 ...

  10. (5)go-micro微服务domain层开发

    目录 一 domain层介绍说明 二 model层开发 三 repository层开发 四 service层开发 五 最后 一 domain层介绍说明 domain层专注于数据库数据领域开发,我们把数 ...