当前位置: 首页 > news >正文

GetDlgItem的用法小结

GetDlgItem用于获得指定控件ID的窗体指针,函数原型如下:


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.
,那说明,它返回的指针有可能是有效的,有可能是无效的,不建议保存留给后续来使用。那么问题来了,

  • 为什么通过GetDlgItem返回的指针有时稳定,有时不稳定?

  • 在实际应用中,如何正确处理GetDlgItem的返回值?

先回答第一个问题, GetDlgItem返回的数据类型是CWnd*类型,它内部有一个 HWND m_hWnd 句柄成员,该句柄成员是一个4字节(64位程序中为8字节)的无符号整形,它代表内存中对象物理地址列表的索引,索引对应保存的内容是特定对象的物理地址。由于Windows的内存管理策略会定时对空闲内存进行释放、移动等操作,当应用程序再次使用时,系统会重新申请物理内存,所以对象的物理地址会变化,Windows通过句柄来对应用程序屏蔽这种变化。当应用程序要访问对象时,只需要将对应的句柄传递给系统,系统内部会根据句柄检索指向对象的最新地址。

C++中的指针也代表地址。对于应用程序中的不同对象和同类中的不同实例来说,Windows不允许直接通过其地址来访问内核对象,而是通过标识或者索引指针的句柄(HANDLE)来访问对象信息。

上面提到了Windows的内存管理策略会对空闲对象内存进行相关操作,据此推测,在Windows认为应用程序空闲时,就会对应用程序的空闲对象进行操作。

GetDlgItem实际上是调用CWnd::FromHandle函数来实现功能的,先看CWnd::FromHandle函数


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函数的官方解释:

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状态的处理:

5c18b658eb979.jpg

基于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这类的函数,随用随取,不要保存另作它用

相关文章:

  • MySQL——索引基础
  • 用Go语言实现微信支付SDK
  • 文档和元素的几何滚动
  • Java编程——数据库两大神器:索引和锁
  • 80% UI 初学者走过的弯路,你走了几条?
  • Numpy数值计算基础
  • MYSQL设置查询内存表大小
  • 聊聊rocketmq的FileAppender
  • JS高级
  • MongoDB4.0构建分布式分片群集
  • (六)Hibernate的二级缓存
  • 用 PreparedStatement 向 SqlServer 中一次性插入多条记录
  • redis的高级特性
  • 新版ExTiX 诞生,基于 Ubuntu 的桌面 Linux 发行
  • 移动端测试===从安卓手机截图到桌面的几行代码
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • create-react-app做的留言板
  • express + mock 让前后台并行开发
  • linux学习笔记
  • PHP 的 SAPI 是个什么东西
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • web标准化(下)
  • 彻底搞懂浏览器Event-loop
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 你真的知道 == 和 equals 的区别吗?
  • 深度学习中的信息论知识详解
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 我有几个粽子,和一个故事
  • 详解NodeJs流之一
  • 小程序01:wepy框架整合iview webapp UI
  • 1.Ext JS 建立web开发工程
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #{}和${}的区别?
  • #android不同版本废弃api,新api。
  • #vue3 实现前端下载excel文件模板功能
  • $forceUpdate()函数
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (03)光刻——半导体电路的绘制
  • (06)Hive——正则表达式
  • (2015)JS ES6 必知的十个 特性
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)setTimeout 和 setInterval 的区别
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • ..回顾17,展望18
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net MySql
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • [ 手记 ] 关于tomcat开机启动设置问题
  • [20161101]rman备份与数据文件变化7.txt
  • [20170705]diff比较执行结果的内容.txt