注:以下以名为Test的对话框工程为例讲解

对话框程序中,如果我们有拖标准控件到界面中,并且有和控件类变量绑定,则会有

void CTestDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BTN_TEST, m_testBtn);
    DDX_Control(pDX, IDC_BUTTON1, m_btnTest);
}
1
2
3
4
5
6
void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl) 
其中DDX_Control用于将ID为nIDC的控件与类型为CWnd的变量rControl绑定 
实际上 
(1)执行了子类化也即改写了Windows标准控件的窗口过程函数为MFC中通用的窗口过程函数 
(2)将rControl与nIDC对应控件的HWnd窗口句柄绑定,并将在MFC全局的HWND与CWnd的Map表中增加一项

[dlgdata.cpp]

void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{
    if (rControl.m_hWnd == NULL)
    {
        HWND hWndCtrl;
        pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
        rControl.SubclassWindow(hWndCtrl);  //子类化
    }
}
1
2
3
4
5
6
7
8
9
[wincore.cpp]

BOOL CWnd::SubclassWindow(HWND hWnd)
{
    if (!Attach(hWnd))
        return FALSE;

PreSubclassWindow();

WNDPROC* lplpfn = GetSuperWndProcAddr();
    //子类化控件,使其窗口过程函数为MFC的通用窗口过程函数
    WNDPROC oldWndProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC,
                                                     (INT_PTR)AfxGetAfxWndProc());

if (*lplpfn == NULL)
        *lplpfn = oldWndProc;   //保存下来

return TRUE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[wincore.cpp]

WNDPROC AFXAPI AfxGetAfxWndProc()
{
#ifdef _AFXDLL
    return AfxGetModuleState()->m_pfnAfxWndProc;
#else
    return &AfxWndProc;
#endif
}
1
2
3
4
5
6
7
8
MFC中通用的窗口过程函数如下: 
[wincore.cpp]

LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
    CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);  //从HWND获取对应的CWnd*
    if (pWnd == NULL || pWnd->m_hWnd != hWnd)
        return ::DefWindowProc(hWnd, nMsg, wParam, lParam);

return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
1
2
3
4
5
6
7
8
[wincore.cpp]

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
                              WPARAM wParam = 0, LPARAM lParam = 0)
{
    LRESULT lResult;
    //通用的窗口过程函数中具体消息的处理转化为类的成员函数去处理
    lResult = pWnd->WindowProc(nMsg, wParam, lParam);   
    return lResult;
}
1
2
3
4
5
6
7
8
[wincore.cpp]

LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT lResult = 0;
    if (!OnWndMsg(message, wParam, lParam, &lResult))   //在消息映射表找到对应的处理函数进行处理
        lResult = DefWindowProc(message, wParam, lParam);  //没有找到则调用未子类化之前的窗口过程函数处理
    return lResult;
}
1
2
3
4
5
6
7
[wincore.cpp]

LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
    if (m_pfnSuper != NULL)
        return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);

WNDPROC pfnWndProc;
    if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
        return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);
    else
        return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);
}
1
2
3
4
5
6
7
8
9
10
11
很显然,通过DDX_Control,标准控件绑定后虽然有子类化即改写了窗口过程函数. 
但是消息的处理基本上是通过pfnWndProc即未绑定前的那个标准窗口过程函数处理的. 
对于自绘控件而言,我们会去写一些诸如DrawItem,MeasureItem,OnPaint等消息处理函数, 
这时候子类化才真正发挥了作用.

如果我们仅仅在MFC中将控件拉到界面中而没有和任何CButton,CEdit等控件变量绑定, 
也即没有调用DDX_Control,则我们没有子类化这种控件,它们的窗口过程函数就是Windows 
对应标准控件的标准窗口过程函数而没有被MFC改写. 
同时该控件的窗口句柄没有和任何CWnd对象绑定,也即在MFC全局的HWND与CWnd的Map表是没有 
该控件Item的. 
在这种情况下,我们调用::GetDlgItem获取该控件的窗口句柄,再调用CWnd::FromHandlePermanent 
获取的CWnd指针为NULL,因为Map表中不存在.

原文:https://blog.csdn.net/hisinwang/article/details/45786719

深入浅出MFC:DDX_Control本质探究相关推荐

  1. 21、深入浅出MFC学习笔记,Application Framework简介

    1.Application Framework是一个完整的程序模型:是一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务.<?xml:namespace prefix ...

  2. return本质探究以及try-finaly下的return探究

    return本质探究 其实reutrn语句本质上我们可以把它分为两步         1.return语句获取到变量的地址         2.return将获取的地址返回,也就是return本质是传 ...

  3. 深入浅出MFC学习笔记

    深入浅出MFC学习笔记 ithzhang CSDN博客:http://blog.csdn.net/ithzhang/article/category/1159054 转载于:https://blog. ...

  4. 28、深入浅出MFC学习笔记,View功能的加强和重绘效率的提高

    1.同一份Document的多个views,在Document的一个view改变了后,如何同步其它view呢? 让所有的Views 同步更新资料的关键在于两个函数: 1)CDocument::Upda ...

  5. 不要看《深入浅出MFC》!

    开篇先声明一点,<深入浅出MFC>是一本不错的书,对于MFC原码的剖析,十分到位,特别是前面对于MFC六大关键技术的总结和演示程序,尤其精彩.那为什么我要说不要看这本书呢?     我是站 ...

  6. 玩转MFC文档视图架构编程1——深入浅出MFC文档/视图架构之基本概念深入浅出MFC文档/视图架构之文档

    原创地址: 深入浅出MFC文档/视图架构之基本概念 http://iis.xrtvu.com/Tech/ShowArticle.asp?ArticleID=276 深入浅出MFC文档/视图架构之文档模 ...

  7. 《深入浅出MFC》观后有感

    <深入浅出MFC>观后有感 本文原创,如需转载,请注明出处! 好几年前我曾经买过这本书,知道它是本好书,在匆匆走马观看一遍后,便将它束之高阁,后来有友人借之,不想几经辗转,最终不知我的这本 ...

  8. 重提“不要看《深入浅出mfc》!”一文

    上次写了"不要看<深入浅出MFC>!"一文后,没想到会引起这么大的反响,看了大家的评论后,我觉得有些朋友误解了我的意思,我有必要在这里重新说一下. 首先就是为什么起这个 ...

  9. 读侯俊杰的《深入浅出MFC》小记

    1.程序必须在产生窗口之前先利用API函数RegisterClass设定属性(我们称此操作为注册窗口类) 2.消息循环中的TranslateMessage是为了将键盘消息转化,DispatchMess ...

最新文章

  1. MASK-RCNN是什么?MASK(掩膜)又是什么?
  2. 网络编程学习笔记(gai_strerror函数)
  3. 3次握手中的最后一个ACK服务端收到了吗
  4. 16-爬虫之scrapy框架手动请求发送实现全站数据爬取03
  5. 图论 —— AOE 网与关键路径
  6. 右手残疾学计算机学什么专业好,我是右手和右脚残疾 左手和左脚好的 可以学残疾人驾照吗...
  7. python xlrd 读取excel
  8. android adb工具命令大全
  9. ios 视频播放器:AVPlayer(附:seektotime精准定位)
  10. 含泪整理最优质QuickTime软件插件素材,你想要的这里都有
  11. android动态指示箭头,android – 自定义选项卡指示器(箭头像指示器)
  12. Oracle随机抽样sample使用说明
  13. FineBI 的多系列折线图
  14. 【新观点】孙悟空其实是太上老君炼的丹药变成的
  15. JMockit使用总结
  16. C#WinForm文本框记忆上次输入文本内容
  17. 真·富文本编辑器的演进之路
  18. Vue菜鸟入门--搭建项目
  19. 计算机辅助写字技术,计算机辅助写字教学论文.doc
  20. Matplotlib饼图显示部分数据标签

热门文章

  1. python时间函数详解_Python:Numpy库基础分析——详解datetime类型的处理
  2. UE4学习-自定义相机视图
  3. mysql run sql files_如何在Eclipse DTP中運行多個.sql文件
  4. 如意报表插件如何安装_Google Chrome浏览器如何安装插件应用
  5. oracle 加全文索引,oracle全文索引的创建和使用
  6. c语言for要分号错误,c语言for语句
  7. java 数字表示什么意思是什么,读取Java字节码指令:数字是什么意思?
  8. 现在的python版本_现在python 流行哪个版本
  9. python改文件名_python批量修改文件名、批量修改xml文件的path和filename
  10. VHDL编码器和译码器的设计