日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入浅出MFC:DDX_Control本质探究

發布時間:2023/12/18 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出MFC:DDX_Control本质探究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

注:以下以名為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本质探究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。