接上文【MFC】05.MFC第一大機(jī)制:程序啟動(dòng)機(jī)制-筆記,這一篇文章來帶領(lǐng)大家逆向分析MFC第二大機(jī)制:窗口創(chuàng)建機(jī)制的源碼。
我們知道,在Win32編程中,如果我們要?jiǎng)?chuàng)建一個(gè)窗口,基本步驟為:
- 注冊(cè)窗口
- 創(chuàng)建一個(gè)窗口,必須要給一個(gè)類名稱
- 消息處理回調(diào)函數(shù)
那么MFC的窗口創(chuàng)建機(jī)制又是怎樣的呢?我們來回溯一下MFC源碼:
首先,我們繼續(xù)用上文中創(chuàng)建的MFC程序:
#include <afxwin.h>
//實(shí)現(xiàn)我們自己的框架類
class CMyFrameWnd :public CFrameWnd {
public:
};
//實(shí)現(xiàn)我們自己的應(yīng)用程序類
class CMyApp :public CWinApp {
public:
CMyApp() {};
//重寫虛函數(shù)
virtual BOOL InitInstance() {
CMyFrameWnd* pFrame = new CMyFrameWnd;
pFrame->Create(NULL, L"FirstMFC");
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
};
CMyApp theApp;
不難猜到,創(chuàng)建窗口的代碼在這:pFrame->Create(NULL, L"FirstMFC");
我們就在這行代碼上下斷點(diǎn),跟過去:
我們知道我們重寫的的InitInstance函數(shù)在WinMian函數(shù)轉(zhuǎn)發(fā)的AfxwWimMian函數(shù)中會(huì)被調(diào)用:
這里給的參數(shù),第一個(gè)NULL是lpszClassName(窗口類名),第二個(gè)參數(shù)是lpszWindowName(應(yīng)用程序類名),但是我們了解Win32編程,我們知道如果想要?jiǎng)?chuàng)建窗口或者是注冊(cè)窗口,都必須要窗口類名,但是這里給的是NULL,為什么還是能夠正常執(zhí)行過去呢?
virtual BOOL InitInstance(){
CMyFrameWnd* pFrame = new CMyFrameWnd;
//Create函數(shù)是框架類的方法:
//我們知道Create方法的參數(shù)肯定不止倆,我們跟過去之后,發(fā)現(xiàn)其他參數(shù)是有默認(rèn)參數(shù)的
pFrame->Create(NULL, L"FirstMFC")
{
//進(jìn)入函數(shù)第一件事:判斷是否包含菜單,如果包含菜單,則加載菜單
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, ATL_RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");
PostNcDestroy();
return FALSE;
}
}
m_strTitle = lpszWindowName; // save title for later
//這里的代碼很明顯是創(chuàng)建窗口了,但是沒有窗口類名,怎么能創(chuàng)建窗口呢?我們跟進(jìn)去看看:
//這里由于其他參數(shù)我們不關(guān)注,這里只留下窗口類名
//這里源代碼函數(shù)實(shí)現(xiàn)實(shí)在if語(yǔ)句的條件中執(zhí)行的,這里直接拉出來
CreateEx( lpszClassName, lpszWindowName,...)
{
//可以看到在這里有斷言:
ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
AfxIsValidAtom(lpszClassName));
ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
//這里是創(chuàng)建窗口所需要的類:
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
//這里隱含的this指針:框架類窗口
PreCreateWindow(cs){
//跟進(jìn)去函數(shù)也能發(fā)現(xiàn)是框架類窗口的方法
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
if (cs.lpszClass == NULL)
{
//發(fā)現(xiàn)這里有一個(gè)貌似MFC注冊(cè)窗口的函數(shù):跟進(jìn)去看看
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)){
//這些是所需要的類,相信大家都很熟悉了
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults
wndcls.lpfnWndProc = DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hCursor = afxData.hcurArrow;
//接下來發(fā)現(xiàn)了好多類似的代碼,應(yīng)該是判斷一些東西,我們的代碼進(jìn)入了這個(gè)if語(yǔ)句,我們就跟進(jìn)去
if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
{
//這里是對(duì)wndcls做一些賦值操作
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
//代碼跟到這里,應(yīng)該是注冊(cè)窗口了,因?yàn)榘勺?cè)窗口所需要的類傳進(jìn)去了,為了以防萬(wàn)一,我們跟進(jìn)去看看:
if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME)){
//代碼前部分做了一些賦值操作,加載圖標(biāo)
//我們跟到這個(gè)函數(shù)中看看注冊(cè)操作:
return AfxRegisterClass(pWndCls){
WNDCLASS wndcls;
//這里的GetClassInfo是判斷窗口是否已經(jīng)注冊(cè)過
GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,&wndcls)
//在這里發(fā)現(xiàn)了Win32API:注冊(cè)窗口
if (!RegisterClass(lpWndClass))
}
}
}
//在注冊(cè)玩窗口后,發(fā)現(xiàn)了這段代碼
//這里的_afxWndFrameOrView是一個(gè)宏或者數(shù)組,跟過去看看,發(fā)現(xiàn)是個(gè)數(shù)組
//跟到最后,發(fā)現(xiàn)是FrameOrView
cs.lpszClass = _afxWndFrameOrView;
}
}
...
return TRUE;
}
}
}
//在創(chuàng)建窗口之前,發(fā)現(xiàn)埋下了一個(gè)鉤子
AfxHookWindowCreate(this){
void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
{
//MFC的第三個(gè)全局變量
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_pWndInit == pWnd)
return;
//這里是埋下了一個(gè)創(chuàng)建窗口的消息鉤子
pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
//如果失敗的話,拋出異常
if (pThreadState->m_hHookOldCbtFilter == NULL)
AfxThrowMemoryException();
}
//這里保存了我們的框架類窗口對(duì)象
pThreadState->m_pWndInit = pWnd;
}
}
//發(fā)現(xiàn)這里是創(chuàng)建窗口
HWND hWnd = CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
}
}
觸發(fā)的鉤子函數(shù)
LRESULT CALLBACK _AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
//MFC第三個(gè)全局變量的地址
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
//取出結(jié)構(gòu)體參數(shù)
LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
//多態(tài) 父類指針 指向子類
CWnd* pWndInit = pThreadState->m_pWndInit
//創(chuàng)建的窗口句柄
HWND hWnd = (HWND)wParam;
//窗口句柄傳入了進(jìn)去
//內(nèi)部this指針是我們的對(duì)象
pWndInit->Attach(hWnd);
{
//MAP對(duì)象
CHandleMap* pMap = afxMapHWND(TRUE);
{
//MFC 第二個(gè)全局變量 線程模塊狀態(tài)
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
//把映射類對(duì)象 保存到了 第二個(gè)全局變量里面
pState->m_pmapHWND = new CHandleMap
return pState->m_pmapHWND;
}
//內(nèi)部this指針是誰(shuí) pMap映射類對(duì)象
pMap->SetPermanent(this->m_hWnd = hWndNew, 框架類對(duì)象);
{
inline void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)
{
//pMap映射類對(duì)象
this->m_permanentMap[窗口句柄] = 框架類對(duì)象 pFrame;
//stl map map[key] = val
}
}
WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,(DWORD_PTR)afxWndProc);
}
LRESULT lResult = CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,wParam, lParam);
}
//真正的窗口過程處理函數(shù)
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
{
CHandleMap* pMap = afxMapHWND();
{
AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
pState->m_pmapHWND
}文章來源:http://www.zghlxwxcb.cn/news/detail-632385.html
return (CObject*)m_permanentMap.GetValueAt((LPVOID)h);
}
AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam)
{
//父類指針 指向了子類
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
}
}文章來源地址http://www.zghlxwxcb.cn/news/detail-632385.html
到了這里,關(guān)于【MFC】06.MFC第二大機(jī)制:窗口創(chuàng)建機(jī)制-筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!