关于SelectObject之后是否要恢复之前的GDI对象
以下列代码为例
{
// 创建内存DC
CDC mMemDc;
mMemDc.CreateCompatibleDC( &dc );
// 创建兼容位图
CBitmap bmpMemBmp;
bmpMemBmp.CreateCompatibleBitmap( &mMemDc, , );
CBitmap* pOldBmp = mMemDc.SelectObject( &bmpMemBmp );
// 在内存DC上绘图
BOOL bRet = mMemDc.Ellipse( , , , );
// 从内存DC上拷贝至显示DC
dc.BitBlt( , , , , &mMemDc, , , SRCCOPY );
// 恢复
// When you finish with the CBitmap object created with the
// CreateCompatibleBitmap function, first select the bitmap out of the device context, then delete the CBitmap object.
//mMemDc.SelectObject( pOldBmp );
}
以上代码最后被注释的部分,按照MSDN上的说法,要将之前的GDI对象SelectObjec回去,防止CBitmap bmpMemBmp中的GDI对象删除失败。
CBitmap析构函数调用基类的~CGdiObject,~CGdiObject中会调用 ::DeleteObject函数来删除GDI对象,关于API函数::DeleteObject(HGDIOBJ hObject) MSDN上有如下说法,if the specified handle is not valid or is currently selected into a DC, the return value is zero.意思是传入的对象句柄无效或者已经被选进DC中的,会返回0,即删除失败。按照这个说法,上文代码最后那部分代码不应该被注释,否则会导致GDI对象删除失败,从而造成资源泄露。
但是,根据实验结果看,并没有造成资源的泄露,使用Process Explorer软件查看GDI句柄数,并没有一直上涨

将GDI对象选入DC, 在没有SelectObject出来之前调用DeleteObject返回的也是成功的,何解?
我想这些都是属于系统底层的机制,为了安全起见,在没有把握的情况下,还是按照官方给出的文档来做,
SelectObject
The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type.
HGDIOBJ SelectObject(
HDC hdc, // handle to DC
HGDIOBJ hgdiobj // handle to object
);
Remarks
This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object.
注:MFC那边的SelectObject,即CDC::SelectObject, 也需要遵循这个规则,查看MFC得知,MFC对这个并没有额外的去处理,^-^
补充:
直接用WIN32缩写,也验证了上面的论点,GDI对象在DC中,DeleteObject能删除成功,
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
return (); case WM_PAINT:
{
hdc = BeginPaint (hwnd, &ps);
TCHAR szStr[] = TEXT("A Window!");
TextOut (hdc, , , szStr, _countof(szStr) ); HPEN hPen = CreatePen( PS_DASH, , RGB(, , ) );
HPEN hOldPen = (HPEN)SelectObject( hdc, (HGDIOBJ)hPen ); Ellipse( hdc, , , , ); // 以下也能删除成功,这个hPen还在dc中
BOOL bRet = DeleteObject( (HGDIOBJ)hPen ); EndPaint (hwnd, &ps);
return ();
}
case WM_DESTROY:
PostQuitMessage ();
return ();
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
结论:为了安全起见,遵循MSDN文档上的约定
关于SelectObject之后是否要恢复之前的GDI对象的更多相关文章
- GDI编程
图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...
- GDI编程小结
图形设备接口(GDI)是一个可运行程序,它接受Windows应用程序的画图请求(表现为GDI函数调用),并将它们传给对应的设备驱动程序,完毕特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...
- VC++学习之GDI概述
VC++学习之GDI概述 图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏 ...
- MFC/Windows API 使用过的函数(持续更新)
/*******************使用默认画笔对象**************************** // //绘制矩形 pDC->MoveTo(50, 50); //返回值是一个指 ...
- 浅谈Windows API编程
WinSDK是编程中的传统难点,个人写的WinAPI程序也不少了,其实之所以难就难在每个调用的API都包含着Windows这个操作系统的潜规则或者是windows内部的运行机制…… WinSDK是编程 ...
- ORACLE恢复数据
ORACLE恢复删除表或表记录 一:表的恢复 对误删的表,只要没有使用PURGE永久删除选项,那么从flash back区恢复回来希望是挺大的.一般步骤有: 1.从flash back里查询 ...
- Oracle DB 执行表空间时间点恢复
• 列出在执行表空间时间点恢复(TSPITR) 时会发生的操作 • 阐释TSPITR 使用的术语的定义 • 确定适合将TSPITR 用作解决方案的情况 • 确定时间点恢复的正确目标时间 • 确定不能使 ...
- iOS开发 - 数据归档与恢复 NSKeyedArchiver
归档与恢复归档 归档,英文Archiver['ɑrkɪvə],这里指的是将OC的对象存储为一个文件或者网络上的一个数据块. 恢复归档.英文UnArchiver,指的是将一个来自文件或网络的归档数据块恢 ...
- 【RMAN】TSPITR--RMAN表空间基于时间点的自动恢复
[RMAN]TSPITR--RMAN表空间基于时间点的自动恢复 一.1 BLOG文档结构图 一.2 前言部分 一.2.1 导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其 ...
随机推荐
- Git安装及SSH Key管理之Windows篇
一.安装环境 1.本机系统:Windows 10 Pro(64位)2.Git版本:Git-2.11.0-64-bit.exe(64位) 二.Git安装 去官网下载完后一路下一步完成安装,如下图: ...
- navicat小经验和快捷键
1.有时按快捷键Ctrl+F搜某条数据的时候搜不到,但是能用sql查出来,这是怎么回事? Ctrl+F只能搜本页数据,不在本页的数据搜不到,navicat每页只显示1000条数据.在数据多的时候nav ...
- PHP网站http替换https
PHP网站http替换https
- 理解MySql事务隔离机制、锁以及各种锁协议
一直以来对数据库的事务隔离机制的理解总是停留在表面,其内容也是看一遍忘一边.这两天决定从原理上理解它,整理成自己的知识.查阅资料的过程中发现好多零碎的概念假设串起来足够写一本书,所以在这里给自己梳理一 ...
- leetCode 104.Maximum Depth of Binary Tree(二叉树最大深度) 解题思路和方法
Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...
- Error (167005): Can't assign I/O pad "GX_TX" to PIN_AG27 because this causes failure in the placement of the other atoms in its associated channel
1.同时在两个GX的bank,建立两GX ip core 会出现 两个IP的cal_blk_clk信号,要保持是同一个时钟
- UltimateRecyclerView的用法具体解释
近期在用非常多第三方库的时候,发现有一些附带的demo写的不是非常全面或者样例的代码太多,凝视太少,要想使用还要去看下源代码什么的(.. .用第三方开源库不就是想节省时间嘛).所以决定每周两到三篇.写 ...
- Linux 中权限的再讨论( 上 )
前言 在Linux系统中,用户分为三个部分( 所有者 同组人 其他 ).每个部分的权限又可以赋予读/写/执行权限.这样,文件的权限标记一共包含 9 个权限位.好了,很多朋友对于Linux权限的了解就仅 ...
- Aspose.cells 读取Excel表中的图片问题
一.说明 本文主要是讲解,怎么使用aspose.cells读取Excel表中的图片,并把图片转换成流或是image对象. 二.开发环境说明 开发工具vs2012,c#语言, 三.Aspose.cell ...
- Hadoop实战-MapReduce之倒排索引(八)
倒排索引 (就是key和Value对调的显示结果) 一.需求:下面是用户播放音乐记录,统计歌曲被哪些用户播放过 tom LittleApple jack YesterdayO ...