mfc学习之主框架窗口创建过程

在上一篇追踪了mfc程序流程之后回到了自己所写的初始化函数

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd * pFrame = new CMyFrameWnd();
	pFrame->Create(NULL,"FirstMFC");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

在上述代码中首先创建了一个pFrame对象,然后执行CMyFrameWnd的成员函数Create,在win32中创建一个窗口首先需要注册窗口类,创建窗口,显示窗口,刷新窗口,消息循环等几个步骤,因此Create函数中应该会执行这几步,在pFrame->Create()代码前加断点,单步调试进入Create函数内部

HMENU hMenu = NULL;
	if (lpszMenuName != NULL)
	{
		// load in a menu that will get destroyed when window gets destroyed
		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();            // perhaps delete the C++ object
			return FALSE;
		}
	}

进入Create函数后首先发现有一个创建菜单的选项,即我们给的lpszMenuName值部位空时会加载菜单然后执行进入CreateEx

进入函数内部发现定义了一个CREATESTRUCT cs;结构体,该结构体类成员如下所示

typedef struct tag CREATESTRUCT
{
    LPVOID lpCreateParams;
    HINSTANCE hInstance;   //应用程序的实例句柄
   HMENU hMenu;           //窗口菜单句柄
   HWND hwndParent;       //父窗口句柄
   int cy;                //指定新窗口的高度,以像素为单位
   int cx;                //指定新窗口的宽度,以像素为单位
   int y;                 //指定新窗口的左上角x坐标
   int x;                 //指定新窗口的左上角y坐标
   LONG style;            //指定新窗口的类型(风格)
   LPCTSTR lpszName;      //指定新窗口的名称
   LPCTSTR lpszClass;     //指定新窗口类的名称
   DWORD dwExStyle;       //指定新窗口扩展风格。
}CREATESTRUCT;

继续单步运行得到

由于我们在create创建时没有给lpszClassName参数赋值,但是注册窗口类时lpszClassName为NULL肯定是不行,因此,mfc应该会在后面给cs.lpszClass重新赋值

继续执行代码

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;

AfxGetInstanceHandle()函数获取WinMain的第一个参数,继续执行到PreCreateWindow,将cs结构体传进去重新赋值,单步进入
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgQAAAAiCAIAAACvClbDAAADP0lEQVR4nO2dPW7bMBxHeZ+OsYHMGmLnJI57iAI9Qg7huZfxkBO0hYEOydqBHVQIjPj1FymRovUefggCWhQ/HPNFkm2ph6eTmZ+/fk+NXiWXy6V2FwAAmkE9HE5mlpbBl9cfZgKFw0NpA0MGAAByKshg9Iv2r/i2G+QgAwAAOaVlMCCRQfihMMgAAEDOWmTgPEekkQEAQBHqyCBwYYBrBgAA5VmFDAIPIQMAgAKsQgYcGQAA1EXtDiczyAAAYIOsQgbauIYcLRSCDAAA5Kjd4cVMsXcTLQ0yAACQgwwAAAAZAAAAMgAAAL0RGdxuH7fbx98/3whZLv2fGSGNRu2OL2aQASFpqf5iJiQnG5KBfv++8iilqvfh7pMwyc4qjkKAlpHKoOu6ruuu12umDCbdz2CuzxkUkIFvvehJ24NZoj6T3MnMPeS0O4xo1IFJncnsfM7UxQsBWkYqA/32qN8enT6Y1J78fgbC77j2Uf3IYFgpZpGBttyQs5zNKINJozN/Lt3ivHWRAdw9IRl0Br0MnD5Ia3g7MphrrclZzZc7FGhIBku0+6kQoGXU7ng2M5LB4AAzIx+kNSy8n4G9sZBiMrBPvCSc0kmWgXkGxtmH8DoorO7bp2+YzjnRlgx8U2f3Z9RcuEtmQ85JE+4zMP/uQoCWSZHByAcJrcq/qM5ZIqH6NQPf+iusbheGV15fxdH662wlWt1XGB34qLqzM4HhhFvPb0g+TNFzBNAydY4MCt/P4G5kIG96ZI6wDKLV7YemVjd7MtcaPaMM7P6nPEcALRORwULXDIRHBskm0JuXgbwz8o0l/z5Hq0e3ry6DSeNCBnA3hGSwxLuJeiQyyDGBbk0Gku3TZBBdwctU154F2i7JlEGgIcko5MN0FAK0jFQGc33OoEdyPwPfhw+ElL+AbJ8V8Z1w8O0nvHI59+ZrSFiYVt25E0l136CGjZ3TKJnncEO+SZ40IfGnDKBlpDLgE8gF4lxxSPVJFpngHRlA26j98WwGGRCSGICW2ZAMqn+RGbnvVP+iMUJyovbPZzPIgJC0VH8xE5KTTcgAAADCqP3zVzPIAABggyCD2fj/fkQAgAYpLYMq9zMoAyYAgHb5B/jsU6a/YYloAAAAAElFTkSuQmCC" alt="" />

进入后发现如下代码
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults    
wndcls.lpfnWndProc = DefWindowProc;
其中lpfnWndProc为一个回调函数,即消息处理函数,但是DefWindowProc作消息处理函数会使程序陷入死循环,因此mfc在下面还会继续处理继续单步执行代码


单步进入得到代码
AFX_STATIC BOOL AFXAPI _AfxRegisterWithIcon(WNDCLASS* pWndCls,
	LPCTSTR lpszClassName, UINT nIDIcon)
{
	pWndCls->lpszClassName = lpszClassName;
	HINSTANCE hInst = AfxFindResourceHandle(
		ATL_MAKEINTRESOURCE(nIDIcon), ATL_RT_GROUP_ICON);
	if ((pWndCls->hIcon = ::LoadIconW(hInst, ATL_MAKEINTRESOURCEW(nIDIcon))) == NULL)
	{
		// use default icon
		pWndCls->hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
	}
	return AfxRegisterClass(pWndCls);
}
pWndCls->lpszClassName被重新赋值为 "AfxFrameOrView110sd",即为注册类名,此时可以调用Win32API来注册窗口类了,返回CreateEx中,继续执行得到如下代码


<img src="data:image/png;base64,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" alt="" />

AfxHookWindowCreate显而易见是给程序埋一个钩子,用于修改消息处理函数,单步进入这个函数发现

::SetWindowsHookEx (WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());

 //调用win32API函数在程序中埋下一个钩子,类型为WH_CBT,一旦WM_CREAT出现马上勾到AfxCbtFilterHook

继续跟踪进入钩子处理函数 _AfxCbtFilterHook ( ),发现一个pWndInit->Attach(hWnd)函数,该函数将创建的窗口类对象与实际代表窗口的句柄作

一一绑定,至此,类对象才真正代表了实际窗口

继续执行代码

WNDPROC afxWndProc = AfxGetAfxWndProc();
oldWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC,
		(DWORD_PTR)afxWndProc);

//利用win32Api函数SetWindowLongPtr将窗口处理函数,从DefWindowProc更改为AfxWndPro(真正的处理函数),至此窗口创建完成,虽然还是有很多地方不是特别了解,但也算是对MFC窗口的创建过程有了一个大概的认识

MFC窗口创建总结有以下几点

1.      加载菜单

2.      调用PreCreateWindow函数  设计并注册窗口类

内部调用AfxDeferRegisterClass设计窗口类

 

WNDCLASSwndcls;

wndcls.lpfnWndProc = DefWindowProc;//???????????下面会更改

……

调用_AfxRegisterClassWithIcon内部调用AfxRegisterClass

内部调用windows API函数::RegisterClass注册窗口类

3. 调用AfxHookWindowCreate

1)  将自己new的框架类对象地址(pFrame)保存到当前程序信息中

2)  调用windows API函数SetWindowsHookEx在程序埋下一个类型为WH_CBT的钩子,一旦CreateWindowEx函数执行成功,调用钩子处理函数

4.      执行windows API函数CreateWindowEx创建窗口,钩子将WM_CREATE消息钩到_AfxCbtFilterHook(钩子处理函数)

5.      调用钩子处理函数

1)  将窗口句柄(hWnd)和 框架类对象地址(pFrame)进行一对一的绑定

2)  调用windowsAPI函数SetWindowLongPtr将窗口处理函数更改为AfxWndProc(真正的窗口处理函数)






  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值