博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入浅出MFC:DDX_Control本质探究
阅读量:4303 次
发布时间:2019-05-27

本文共 3029 字,大约阅读时间需要 10 分钟。

注:以下以名为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 
 

你可能感兴趣的文章
学习笔记_vnpy实战培训day04_作业
查看>>
OCO订单(委托)
查看>>
学习笔记_vnpy实战培训day05
查看>>
学习笔记_vnpy实战培训day06
查看>>
Python super钻石继承
查看>>
回测引擎代码分析流程图
查看>>
Excel 如何制作时间轴
查看>>
股票网格交易策略
查看>>
matplotlib绘图跳过时间段的处理方案
查看>>
vnpy学习_04回测评价指标的缺陷
查看>>
ubuntu终端一次多条命令方法和区别
查看>>
python之偏函数
查看>>
vnpy学习_06回测结果可视化改进
查看>>
读书笔记_量化交易如何建立自己的算法交易01
查看>>
设计模式03_工厂
查看>>
设计模式04_抽象工厂
查看>>
设计模式05_单例
查看>>
设计模式06_原型
查看>>
设计模式07_建造者
查看>>
设计模式08_适配器
查看>>