VC++MFC框架窗口(三)CreateEx 函数 Create函数 下载PDB文件

目录

2.创建窗口

CreateEx 函数(afxwin.h)声明:

CreateEx 函数(wincore.cpp)定义:

Create函数(afxwin.h)声明:

Create函数(winfrm.cpp)定义:

下载PDB文件:

3.显示窗口和更新窗口

接上:VC++MFC框架窗口(二)AfxEndDeferRegisterClass 函数(wincore.cpp)

接下:VC++ 消息循环 Run函数 PumpMessage函数 AfxInternalPumpMessage函数


2.创建窗口

按照Win32程序编写步骤,在设计窗口类注册窗口类之后创建窗口。在MFC程序中,窗口的创建功能是由 CWnd 类 CreateEx 函数实现的,该函数的声明位于afxwin.h文件中,具体代码如下所示。

CreateEx 函数(afxwin.h)声明:

	// advanced creation (allows access to extended styles)
    // 高级创建(允许访问扩展样式)  
	virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
		LPCTSTR lpszWindowName, DWORD dwStyle,
		int x, int y, int nWidth, int nHeight,
		HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL);

CreateEx 函数(wincore.cpp)定义:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
	LPCTSTR lpszWindowName, DWORD dwStyle,
	int x, int y, int nWidth, int nHeight,
	HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
	ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
		AfxIsValidAtom(lpszClassName));
	ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));

	// allow modification of several common create parameters
	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;

	if (!PreCreateWindow(cs))
	{
		PostNcDestroy();
		return FALSE;
	}

	AfxHookWindowCreate(this);
	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);

#ifdef _DEBUG
	if (hWnd == NULL)
	{
		TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
			GetLastError());
	}
#endif

	if (!AfxUnhookWindowCreate())
		PostNcDestroy();        // cleanup if CreateWindowEx fails too soon

	if (hWnd == NULL)
		return FALSE;
	ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
	return TRUE;
}

在MFC底层代码中,CFrameWnd类Create函数内部调用了上述CreateEx函数。而前者又由CFrameWnd类的LoadFrame函数调用。CFrameWnd类的Create函数的声明也位于afxwin.h文件中,代码如下。

Create函数(afxwin.h)声明:

	virtual BOOL Create(LPCTSTR lpszClassName,
				LPCTSTR lpszWindowName,
				DWORD dwStyle = WS_OVERLAPPEDWINDOW,
				const RECT& rect = rectDefault,
				CWnd* pParentWnd = NULL,        // != NULL for popups
				LPCTSTR lpszMenuName = NULL,
				DWORD dwExStyle = 0,
				CCreateContext* pContext = NULL);

Create函数(winfrm.cpp)定义:

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
	LPCTSTR lpszWindowName,
	DWORD dwStyle,
	const RECT& rect,
	CWnd* pParentWnd,
	LPCTSTR lpszMenuName,
	DWORD dwExStyle,
	CCreateContext* pContext)
{
	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;
		}
	}

	m_strTitle = lpszWindowName;    // save title for later

	if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
		rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
		pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
	{
		TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");
		if (hMenu != NULL)
			DestroyMenu(hMenu);
		return FALSE;
	}

	return TRUE;
}

CFrameWnd类派生于CWnd类,根据类的继承性原理,CFrameWnd类就继承了CWnd类的CreateEx函数。因此,CFrameWnd类的Create函数内调用的实际上就是CWnd类的CreateEx函数。

提示:在调试Test程序时,会发现无法进入MFC源码设置的断点处,这是因为在Visual Studio 2017默认安装后没有带调试所需要的PDB文件(该文件主要存储了 Visual Studio 调试程序时所需要的基本信息),需要我们自己下载。在Visual Studio开发环境中,单击菜单栏上的【工具】菜单,单击【选项】菜单项,在出现的“选项”对话框中,在左边的列表框中找到“调试”节点,选中“符号”,在右侧选中“Microsoft符号服务器”,同时可以设置一个缓存符号的目录,如图所示。单击“确定”按钮,就可以开始调试运行Test程序,跟踪 MFC的源码了。第一次调试的时候可能会比较慢,这是因为在调试过程中会下载所需的PDB 文件,下载的同时会缓存到我们指定的缓存符号的目录下,后期调试将直接使用本地的PDB文件,就很快了。

下载PDB文件:

在CWnd类的CreateEx函数实现代码中,发现该函数中又调用了 PreCreateWindow 函数(虚函数)。因此,实际上调用的是子类,即CMainFrame 类PreCreateWindow 函数。再次调用这个函数,主要是为了在产生窗口之前让程序员有机会修改窗口外观。例如,去掉窗口的最大化按钮等,PreCreateWindow 函数的参数就是为了实现这个功能而提供的。该参数的类型是CREATETRUCT结构,我们可以把这个结构体与CreateWindowEx函数的参数做一个比较,如下图所示是CREATETRUCT结构和CreateWindowEx函数声明的对比。注意:左边结构体成员与右边函数参数的对应关系。

可以发现,CREATETRUCT结构体中的字段与CreateWindowEx函数的参数是一致的,只是先后顺序相反而已。同时,可以看到PreCreateWindow函数的这个参数是引用类型。这样,在子类中对此参数所做的修改,在其基类中是可以体现出来的。再看看前面 CWnd 类的 CreateEx 函数代码,如果在子类的PreCreateWindow 函数中修改了CREATESTRUCT 结构体的值,那么,接下来调用 CreateWindowEx 函数时,其参数就会发生相应的改变,从而创建一个符合我们要求的窗口。 

知识点:在MFC中后缀名为Ex的函数都是扩展函数。

3.显示窗口和更新窗口

Test程序的应用程序类TestApp从它的基类CWinThread继承了一个名为m_pMainWnd的成员变量(公有成员)。该变量是一个 CWnd 类型的指针,它保存了应用程序框架窗口对象的指针。也就是说,是指向 CMainFrame 对象的指针。在 CTestApp 类的 InitInstance函数实现内部有如下两行代码。

    // 调度在命令行中指定的命令。  如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;//此时窗口创建完成

	// 唯一的一个窗口已初始化,因此显示它并对其进行更新
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

这两行代码的功能是显示应用程序框架窗口和更新这个窗口。

接上:VC++MFC框架窗口(二)AfxEndDeferRegisterClass 函数(wincore.cpp)

接下:VC++ 消息循环 Run函数 PumpMessage函数 AfxInternalPumpMessage函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米酒馆

鼓励鼓励,鼓励很重要啦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值