GetDlgItem用于得到指定控件ID的窗体指针,函数原型以下:html
HWND GetDlgItem( HWND hDlg, int nIDDlgItem ); CWnd* GetDlgItem(int nID) const;
它的使用说明中有这样一行字,The returned pointer may be temporary and should not be stored for later use.
,那说明,它返回的指针有多是有效的,有多是无效的,不建议保存留给后续来使用。那么问题来了,app
为何经过GetDlgItem返回的指针有时稳定,有时不稳定?框架
在实际应用中,如何正确处理GetDlgItem的返回值?ide
先回答第一个问题, GetDlgItem返回的数据类型是CWnd*类型,它内部有一个 HWND m_hWnd 句柄成员,该句柄成员是一个4字节(64位程序中为8字节)的无符号整形,它表明内存中对象物理地址列表的索引,索引对应保存的内容是特定对象的物理地址。因为Windows的内存管理策略会定时对空闲内存进行释放、移动等操做,当应用程序再次使用时,系统会从新申请物理内存,因此对象的物理地址会变化,Windows经过句柄来对应用程序屏蔽这种变化。当应用程序要访问对象时,只须要将对应的句柄传递给系统,系统内部会根据句柄检索指向对象的最新地址。函数
C++中的指针也表明地址。对于应用程序中的不一样对象和同类中的不一样实例来讲,Windows不容许直接经过其地址来访问内核对象,而是经过标识或者索引指针的句柄(HANDLE)来访问对象信息。oop
上面提到了Windows的内存管理策略会对空闲对象内存进行相关操做,据此推测,在Windows认为应用程序空闲时,就会对应用程序的空闲对象进行操做。指针
GetDlgItem其实是调用CWnd::FromHandle函数来实现功能的,先看CWnd::FromHandle函数code
CWnd::FromHandle(HWND hWnd) -->CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist -->AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); -->pState->m_pmapHWND = new CHandleMap -->CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd); -->pWnd->AttachControlSite(pMap);
再看下CWinApp::OnIdle函数,OnIdle函数的官方解释:htm
CWinApp::OnIdle对象
OnIdle is called in the default message loop when the application's message queue is
empty. Use your override to call your own background idle-handler tasks.
MFC程序中对Idle状态的处理:
基于MFC的OnIdle相关流程以下:
CWinApp::OnIdle --> CWinThread::OnIdle(lCount) -->AfxUnlockTempMaps() --> AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); --> pState->m_pmapHWND->DeleteTemp();
对CWinApp:OnIdle进行重载,返回非零表明还有Idle Task要处理,这样下次OnIdle仍然会继续执行。返回0,表示无Idle任务须要处理。具体详细的参考MFC框架程序中的OnIdle
不少函数,如FromHandle、FindWindow都用到了临时对象技术,这些临时对象即用即取,不能保存后另做他用。默认状况下,MFC框架会在空闲时间把临时对象给清空掉。
最后解答开头提出的问题:
当默认Idle流程执行时,会删除临时对象句柄。
对于GetDlgItem这类的函数,随用随取,不要保存另做它用