Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2707738
  • 博文数量: 416
  • 博客积分: 10220
  • 博客等级: 上将
  • 技术积分: 4193
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-15 09:47
文章分类

全部博文(416)

文章存档

2022年(1)

2021年(1)

2020年(1)

2019年(5)

2018年(7)

2017年(6)

2016年(7)

2015年(11)

2014年(1)

2012年(5)

2011年(7)

2010年(35)

2009年(64)

2008年(48)

2007年(177)

2006年(40)

我的朋友

分类: WINDOWS

2007-01-18 09:11:06


Q : MFC返回的临时对象指针成因?
主要解答者: QunKangLi 提交人: QunKangLi
感谢: oldforest、yu_hl、QunKangLi
审核者: happyparrot 社区对应贴子:
     A :

msdn在介绍GetDlgItem的时候,明确指出:  
The  returned  pointer  may  be  temporary  and  should  not  be  stored  for  later  use.  
如果真是这样那我不惨了!在我的一个软件中,因为常常要使切换按钮的可用与不可用以及改变按钮文字,所以我用DetDlgItem把它们存了起来,用的时候直接到数组里面取,这样的话这个软件不是犯了一个重大的错误了?可是用这么久也没出错。  
另外,它也是说可能是临时的,那一定在某种情况下不是临时的,高手能不能解释一下这个问题?  
---------------------------------------------------------------  
//    Most  Windows  objects  are  represented  with  a  HANDLE,  including  
//            the  most  important  ones,  HWND,  HDC,  HPEN,  HFONT  etc.  
//    We  want  C++  objects  to  wrap  these  handle  based  objects  whenever  we  can.  
//    Since  Windows  objects  can  be  created  outside  of  C++  (eg:  calling  
//            ::CreateWindow  will  return  an  HWND  with  no  C++  wrapper)  we  must  
//            support  a  reasonably  uniform  mapping  from  permanent  handles  
//            (i.e.  the  ones  allocated  in  C++)  and  temporary  handles  (i.e.  
//            the  ones  allocated  in  C,  but  passed  through  a  C++  interface.  
//    We  keep  two  dictionaries  for  this  purpose.    The  permanent  dictionary  
//            stores  those  C++  objects  that  have  been  explicitly  created  by  
//            the  developer.    The  C++  constructor  for  the  wrapper  class  will  
//            insert  the  mapping  into  the  permanent  dictionary  and  the  C++  
//            destructor  will  remove  it  and  possibly  free  up  the  associated  
//            Windows  object.  
//    When  a  handle  passes  through  a  C++  interface  that  doesn't  exist  in  
//            the  permanent  dictionary,  we  allocate  a  temporary  wrapping  object  
//            and  store  that  mapping  into  the  temporary  dictionary.  
//    At  idle  time  the  temporary  wrapping  objects  are  flushed  (since  you  better  
//            not  be  holding  onto  something  you  didn't  create).  
//  
 
 
在CWinThread::OnIdle里调用AfxUnlockTempMaps,AfxUnlockTempMaps会释放temporary  maps.  
 
所以不要保留GetDlgItem等返回的临时指针,可以直接保存HWND  objects,然后CWnd::FromHandle获取临时指针来用。  
 
---------------------------------------------------------------  
 
临时包装对象会在空闲时间删除.在同一函数中多次使用是没用问题的,不同函数中使用先前保存下来的指针就有可能出错,特别是对话框初使化时候存下来的指针.  
       在MFC层次上的函数使用CWnd对象,而本地Windows代码(API)使用句柄.如:当Windows系统调用一个窗口过程时将传递一个HWND参数,而MFC本身的消息机制使用CWnd类;为了更好更高效的实现,MFC需要与Windows系统合作,将句柄与CWnd对象进行关联---它用CHandleMap完成关联.  
CHandleMap有两个CMapPtrToPtr的成员变量:m_permanentMap(永久映射表,程序运行过程中对象/句柄之间的关系),m_temporaryMap(临时映射表,在消息存在的过程中才存在).永久表保存显式创建的CWnd对象,当对象创建时将在永久目录下插入一个条目,在CWnd::OnNcDestrory时删除对应条目.但是Windows有时会传入某些不是由开发人员显式创建的窗口的句柄,此时MFC会分配一个临时对象来包装这个句柄并将它们的映射保存到临时映射表中,这些临时对象会在空闲时间被删除并移走相应的临时映射表条目.类似的MFC对象与Windows句柄的映射表有:  
m_pmapHWND:                        窗口句柄与CWnd对象  
m_pampHMENU:                        菜单句柄与CMenu对象  
m_pmapHDC:                        设备环境句柄与CDC对象  
m_pmapHGDIOBJ:                        GDI句柄与CGDI对象  
m_mapHIMAGELIST:            图像链表句柄到CImageList对象  
 
当给定句柄,如HWND时,MFC简单调用CWnd*  PASCAL  CWnd::FromHandle(HWND  hWnd),  此函数内部使用CHandleMap::FromHandle(hWnd)获取相关联的CWnd对象.在CHandleMap::FromHandle(h)内部(源代码在WinHand.cpp),先使用CObject*  pObject  =  LookupPermanent(h);            if  (pObject  !=  NULL)return  pObject;    检查永久表;如永久表中不存在,使用pObject  =  LookupTemporary(h))  !=  NULL检查临时表,都不存在时,使用pTemp  =  =  m_pClass->CreateObject();if  (pTemp  ==  NULL)AfxThrowMemoryException();m_temporaryMap.SetAt((LPVOID)h,  pTemp);创建临时对象并将其插入到临时表中去,同时返回该临时对象.  
void  CHandleMap::RemoveHandle(HANDLE  h)的注释说明临时对象将在空闲时由OnIdel释放:  
      //  remove  only  from  permanent  map  --  temporary  objects  are  removed  
      //    at  idle  in  CHandleMap::DeleteTemp,  always!  
如果想不自动释放临时对象,使用void  AFXAPI  AfxLockTempMaps()/BOOL  AFXAPI  AfxUnlockTempMaps(BOOL  bDeleteTemps)进行锁定.  

HANDLE是如HWND,HDC等的统称
HANDLE:句柄,是Windows用来表示对象的(不是C++的对象),HWND是其中一种,HWND是HANDLE,但HANDLE不只是HWND,更具体的查MSDN


阅读(1286) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~