其实,我的C++入门就是从GDI开始的,想在CE上面写应用程序,若兼程序界面太难看那就必须用回GDI了。GDI是一种古老而又非常麻烦的技术,在C#年代还好点,但VC++下,玩GDI记得最最重要的一点是,一定要注意GDI资源的回收,否则你的程序会没跑几下就弹出错误窗口,原因大概都是内存泄漏。所以凡是遇上CPen,CBrush,CBitmap,GetDC()...等等,请打醒十二分精神。

因为以前吃了太多的亏,原则上我对GDI资源的回收还是挺有自信的,但这世界上总是存在着许多新的状况跟不同的问题的,昨晚认真研究了自己一段有BUG代码,在此作一番记录。

凡在窗体上绘图,必要用到双缓存的技术,而这又离不开两个函数:CreateCompatibleDC与CreateCompatibleBitmap,大概的意思,创建一个跟显示屏幕格式一致的内存段,在此内存段里画好图之后再拷贝到屏幕里(这是我非标准的理解方式),具体的API用法网上有很多很详细的教程,而正常的创建与资源回收的代码如下:

  1. CDC * pDC = this->GetRealDC();//真实的窗体DC,一般在CWnd下使用GetDC()获得
  2. CDC MemDC;
  3. CBitmap bmp;
  4. CBitmap * pBmp = NULL;
  5. CRect rc = this->GetRect();//窗体的尺寸,一般在CWnd类使用GetClientRect()获得
  6. BOOL bRes = FALSE ;
  7. bRes = MemDC.CreateCompatibleDC(pDC);
  8. ASSERT(bRes);
  9. bRes = bmp.CreateCompatibleBitmap(pDC , rc.Width() , rc.Height());
  10. ASSERT(bRes);
  11. pBmp = MemDC.SelectObject(&bmp);
  12. ASSERT(pBmp);
  13. //Do something
  14. //...
  15. //一般兼容DC的回收原则是先创建后删除
  16. MemDC.SelectObject(pBmp);
  17. bRes = pBmp->DeleteObject();
  18. pBmp = NULL;
  19. ASSERT(bRes);
  20. bRes = bmp.DeleteObject();
  21. ASSERT(bRes);
  22. bRes = MemDC.DeleteDC();
  23. ASSERT(bRes);

以上经自己实践检验过的代码,ASSERT()的部分都能通过,表示就是真的可以用,若你喜欢的话完全可以写个while函数来测试一下,若资源没回收的话,程序不到跑100次就已经挂掉了。但如果我在同一个pDC下创建两个MemDC时,回收就会有问题了,代码如下:

  1. CDC * pDC = this->GetRealDC();//真实的窗体DC,一般在CWnd下使用GetDC()获得
  2. CDC MemDC;
  3. CBitmap bmp;
  4. CBitmap * pBmp = NULL;
  5. CRect rc = this->GetRect();//窗体的尺寸,一般在CWnd类使用GetClientRect()获得
  6. CDC MemDC2;
  7. CBitmap bmp2;
  8. CBitmap * pBmp2 = NULL;
  9. BOOL bRes = FALSE ;
  10. bRes = MemDC.CreateCompatibleDC(pDC);
  11. ASSERT(bRes);
  12. bRes = bmp.CreateCompatibleBitmap(pDC , rc.Width() , rc.Height());
  13. ASSERT(bRes);
  14. pBmp = MemDC.SelectObject(&bmp);
  15. ASSERT(pBmp);
  16. bRes = MemDC2.CreateCompatibleDC(pDC);
  17. ASSERT(bRes);
  18. bRes = bmp2.CreateCompatibleBitmap(pDC , rc.Width() , rc.Height());
  19. ASSERT(bRes);
  20. pBmp2 = MemDC2.SelectObject(&bmp2);
  21. ASSERT(pBmp);
  22. //Do something
  23. //...
  24. MemDC.SelectObject(pBmp);
  25. bRes = pBmp->DeleteObject();
  26. pBmp = NULL;
  27. ASSERT(bRes);//通过
  28. bRes = bmp.DeleteObject();
  29. ASSERT(bRes);//通过
  30. bRes = MemDC.DeleteDC();
  31. ASSERT(bRes);//通过
  32. MemDC2.SelectObject(pBmp2);
  33. bRes = pBmp2->DeleteObject();
  34. pBmp2 = NULL;
  35. ASSERT(bRes);//失败
  36. bRes = bmp2.DeleteObject();
  37. ASSERT(bRes);//失败
  38. bRes = MemDC2.DeleteDC();
  39. ASSERT(bRes);//通过

经过调试后的结论是,pBmp与pBmp2是指向的是同一个东西,MemDC.SelectObject(pBmp)这一句话是断开bmp与MemDC的关联,若不事先断开的话bmp.DeleteObject()就会失败,所以一旦先执行了bRes = pBmp->DeleteObject()这一句,那MemDC.SelectObject(pBmp2)这一句就存在问题了(事实上pBmp2已经被删掉了),导致后面全线崩溃。于是,如果是双兼容DC的话,其正常的回收代码应该如下所示。总之不管三七二十一,先断开兼容DC与兼容位图的关联后,再作相关的资源回收。

  1. MemDC.SelectObject(pBmp);
  2. MemDC2.SelectObject(pBmp2);
  3. bRes = pBmp->DeleteObject();
  4. ASSERT(bRes);
  5. if (pBmp2 != pBmp)
  6. {
  7. bRes = pBmp2->DeleteObject();
  8. ASSERT(bRes);
  9. }
  10. pBmp = NULL;
  11. pBmp2 = NULL;
  12. bRes = bmp.DeleteObject();
  13. ASSERT(bRes);//通过
  14. bRes = MemDC.DeleteDC();
  15. ASSERT(bRes);//通过
  16. bRes = bmp2.DeleteObject();
  17. ASSERT(bRes);//通过
  18. bRes = MemDC2.DeleteDC();
  19. ASSERT(bRes);//通过

转载于:https://blog.51cto.com/joeyliu/1056147

CreateCompatibleBitmap,关于兼容DC的创建与资源回收相关推荐

  1. Win32 位图 - BitBlt,内存兼容DC,LoadBitmap

    注:以下内容为学习笔记,多数是从书本.资料中得来,只为加深印象,及日后参考.然而本人表达能力较差,写的不好.因非翻译.非转载,只好选原创,但多数乃摘抄,实为惭愧.但若能帮助一二访客,幸甚! 学了一周左 ...

  2. 《ActionScript 3.0基础教程》——第2章 往舞台动态地添加对象2.1 创建库资源,并为它命名...

    本节书摘来自异步社区<ActionScript 3.0基础教程>一书中的第2章,第2.1节,作者: [美]Doug Winnie 更多章节内容可以访问云栖社区"异步社区" ...

  3. 通过案例了解puppet创建虚拟资源解决资源冲突问题

    通过案例了解puppet创建虚拟资源解决资源冲突问题 虚拟资源是一种用来管理多种配置共同依赖同一资源的方法.如果多个类依赖同一个资源时则可避免写多个资源,也可以解决资源重定义的错误. 虚拟资源经常用于 ...

  4. Android复习15【动画:创建资源文件夹、创建动画资源文件、组合动画、属性动画、材料设计新特性】

    2020-05-09-[12周-周四] Android动画 https://blog.csdn.net/zhangbijun1230/article/details/80262359 https:// ...

  5. 用Restlet创建面向资源的服务

    http://www.infoq.com/cn/articles/restlet-for-restful-service Restlet项目(http://www.restlet.org)为" ...

  6. 试图共享文件夹时出现错误,没有启动服务器服务,此时尚未创建共享资源,试图共享时出现错误,没有启动服务器服务,此时尚未创建共享资源...

    试图共享时出现错误,没有启动服务器服务,此时尚未创建共享资源.txt 1.如果"文件打印和共享"协议已安装,但在需要共享的文件夹上单击右键没有"共享"菜单.解决 ...

  7. 2017-06-13共享时出现错误,没有启动服务器服务,此时尚未创建共享资源”的解决办法

    1.原因windows xp 不能共享 处理了 computer brower+server 都正常,只是windows 防火墙不能启动 后来使用了windowsrepair解决了些问题!在些给大家提 ...

  8. Android Studio项目中常见的需要自行创建的资源文件夹的位置(assets、raw、menu、anim等)

    写项目过程中,常遇到一些需要自行创建的资源文件夹时,容易忘记位置,现图示一下常见的资源文件夹的位置(Project 结构):                  

  9. 飞康应用——虚拟磁盘和创建SAN资源

    点击"重新扫描" 选择"发现新设备",点击"确定" 在"重新扫描状态"对话框中选择"物理设备",可以 ...

最新文章

  1. javascript 循环语句 while、do-while、for-in、for用法区别
  2. php 获取class id,CSS Class 與 CSS ID
  3. Android什么是函数,什么是函数响应式编程(JavaAndroid版本)
  4. Java Web学习(七)HttpServletResponse(客户端响应)
  5. Java 集合系列07之 Stack详细介绍(源码解析)和使用示例
  6. Flutter文本输入框TextField控制器TextEditingController,TextField预设内容,获取TextField中的输入内容,兼听TextField中的内容变化
  7. 三星Galaxy Note10系列带壳渲染图曝光:将取消3.5mm耳机孔
  8. [UOJ336]无限之环
  9. 排序算法3:最常用的排序——快速排序
  10. 简化超长的函数指针类型
  11. 网络通信的发展和基础原理
  12. 关于输入法图标消失 只能输入英文 win10 语言选项 键盘那里显示 输入法仅桌面的解决办法
  13. 机动车验车需要的材料和流程(转载)
  14. 关于NMDS的一知半解
  15. 基于Python的指数基金量化投资-通过市盈率和市净率对指数估值
  16. C语言变量inv,编写一个函数inv,将数组a中n个整数按相反顺序存放,用指针变量作为调用该函数时的实参...
  17. Python编程学习第一篇——Python零基础快速入门(三)——10行代码画朵花
  18. pycharm如何设置官方中文?pycharm如何汉化?pycharm终于支持官中了!!!
  19. Windows系统图片不显示缩略图如何解决
  20. lsnrctl 未找到命令

热门文章

  1. 码率/分辨率信息汇总
  2. 趣谈12星座 这个貌似挺准的
  3. Mysql入门学习(二)之子查询+关联
  4. 端口22以及与SSH协议的关系
  5. vb 获取计算机序列号,VB.net获取CPU与硬盘物理序列号与容量的实例
  6. Android 自定义View实现炮弹射击小游戏
  7. 整站翻译,英文网页批量翻译成中文
  8. 为什么用SolidWorks那么久你还是一个初学者?
  9. Android Tv 小米遥控器,小米电视遥控器怎么样?小米电视支持手机遥控吗?
  10. Android svg矢量图实现心跳动画