MFC启动过程(一)

#include <windows.h>
#include <stdio.h>

LRESULT CALLBACK WinSunProc(
	HWND	hwnd,
	UINT	uMsg,
	WPARAM	wParam,
	LPARAM	lParam
	);

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR	  lpCmdLine,
	int  nCmdShow
	)
{	
	WNDCLASS wndcls;
	wndcls.cbClsExtra = 0;
	wndcls.cbWndExtra = 0;
	wndcls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
	wndcls.hIcon = LoadIcon (NULL,IDI_ERROR);
	wndcls.hCursor = LoadCursor (NULL,IDC_CROSS);
	wndcls.hInstance = hInstance;
	wndcls.lpfnWndProc = WinSunProc;	//这个是什么函数?自己写的吗?
	wndcls.lpszClassName = "wenxin";
	wndcls.style = CS_HREDRAW | CS_VREDRAW;
	wndcls.lpszMenuName = NULL;

	RegisterClass(&wndcls);	//注册窗口类

	HWND hwnd;
	hwnd = CreateWindow ("wenxin","测试窗口", WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL );
	ShowWindow (hwnd, SW_SHOWNORMAL);
	UpdateWindow (hwnd);

	MSG  msg;
	while (GetMessage (&msg, NULL, 0, 0 ))
	{
		TranslateMessage (&msg);
		DispatchMessage (&msg);
	}
	return 0;



}


LRESULT CALLBACK WinSunProc(
	HWND	hwnd,
	UINT	uMsg,
	WPARAM	wParam,
	LPARAM	lParam
	)
{
	switch(uMsg)
	{
	case WM_CHAR:
		char szChar[20];
		sprintf (szChar , "char is %d",wParam);
		MessageBox(hwnd,szChar,"wenxin",0);
		break;
	case WM_LBUTTONDOWN:
		MessageBox(hwnd,"mouse clicked","wenxin",0);
		HDC hdc;
		hdc = GetDC(hwnd);
		TextOut (hdc,0,50,"测试窗口",strlen("测试窗体"));
		ReleaseDC (hwnd,hdc);
		break;
	case WM_PAINT:
		HDC hDC;
		PAINTSTRUCT ps;
		hDC = BeginPaint(hwnd,&ps);
		TextOut(hDC,0, 0, "个性飞扬",strlen("个性飞扬"));
		EndPaint(hwnd,&ps);
		break;
	case WM_CLOSE:
		if(IDYES == MessageBox(hwnd,"是否真的结束?","要退出第一个写的程序吗?",MB_YESNO))
		{
			DestroyWindow(hwnd);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);

		break;
	default:
		return DefWindowProc(hwnd,uMsg, wParam, lParam);
	}

	return 0;
}

以上代码是产生一个小的简单的窗体,这个窗体虽然简单,但是所有的机制都还算健全。先分析这些代码能帮我们理解windows的运行机制。

首先代码中声明了一个函数WndSunProc(),这个函数有一个特殊的关键字CALLBACK,经这个关键字定义的函数为回调函数,供操作系统调用,对于CALLBACK关键字这里不再做其他的解释。

接下来便是程序的启动函数WinMain(),程序启动时便会进入此函数,在此函数中首先定义了WNDCLASS类型的对象(这里暂称wndcls为对象),接下来对wndcls便做了很多的赋值操作,结构WNDCLASS包含一个窗口类的全部信息,也是Windows编程中使用的基本数据结构之一,应用程序通过定义一个窗口类确定窗口的属性在赋值操作中最重要的算是对wndcls.lpfnWndProc的赋值了,这个变量指向了一个函数,窗体有消息需要处理时便会调用此函数来处理消息,因此WndSunProc()函数为消息处理函数,故在下面的代码中在该函数中添加了对部分消息的处理。对wndcls赋值完成之后算是设计好了窗体的外观。接下来便是注册窗口类操作RegisterClass(&wndcls)。

注册好窗体类之后定义了一个窗体句柄变量(hwnd)用来记录建立窗体的句柄,接下来调用CreateWindow()函数来创建一个窗体,这个函数只负责创建窗体,创建的窗体并不能立刻显示出来。之后的ShowWindow()函数负责将窗体显示出来。

窗体显示出来之后还是不能处理任何消息的并且如果不写循环获取消息代码,窗口进程会在建立之后瞬间杀死(具体原因还在分析之中)。所以接下来的代码是循环获取Message消息,并转化处理消息。

WinMain()函数之后的WinSunProc()函数便是消息处理函数的函数体,其中具体的代码这里就不分析了。

这里对最基本、最简单的窗体代码进行了简单的分析,目的是与后面的MFC代码做对比只用。MFC启动过程(二)中将会分析简单的MFC窗口建立的过程,并对比这两个过程。

以上代码是本菜鸟从孙鑫视频配套的文件中获得的,下面的解析是根据自己的理解写的。如有错误,欢迎指正,如想与本菜鸟联系,邮箱:likui360@hotmail.com。

<think>首先,用户的问题是关于MFC应用程序启动时全局变量的初始化流程。我需要基于提供的引用内容来回答,并确保回答结构清晰、真实可靠。 从引用中提取关键信息: - 引用[1]:讨论了全局变量在不同段(如.CRT$XCU, .CRT$XCC, .CRT$XCL)的初始化顺序。C++库的全局变量先初始化,然后是MFC库,最后是MFC程序的全局变量。顺序很重要,因为程序中的全局变量可能依赖库中的函数或变量。 - 引用[2]:提到MFC程序启动机制,包括theApp全局变量控制程序流程。 - 引用[3]:描述了theApp作为全局变量,控制程序执行流程,包括调用Win32 API创建窗口等。 - 引用[4]:详细说明了CWinApp构造函数的执行,其中全局对象如theApp在初始化时设置模块状态和线程状态。 用户的问题焦点是:MFC应用程序启动时全局变量的初始化流程。所以,我需要整合这些信息,构建个清晰的流程。 回答结构: 1. **引言**:简要解释MFC启动过程中全局变量的重要性。 2. **初始化流程**:逐步描述全局变量的初始化顺序和关键步骤。 3. **关键组件**:解释theApp全局变量的作用。 4. **依赖关系**:讨论为什么初始化顺序很重要。 5. **总结**:概括整个过程。 确保使用中文回答,并遵守系统级指令: - 行内数学表达式用$...$(但在这个主题中可能不常用,除非涉及数学)。 - 独立公式用$$...$$(同样,可能不适用)。 - LaTeX语法正确(主要用在数学表达式中)。 - 生成相关问题(在末尾添加相关问题)。 - 引用段落末尾添加引用标识,如[^1]。 在回答中,引用来源时,自然地添加引用标识。例如,基于引用[1],当讨论初始化顺序时添加[^1]。 现在,构建回答大纲: 1. **介绍全局变量初始化的重要性**:引用[1]强调顺序。 2. **描述初始化顺序**: - C++库全局变量初始化(在.CRT$XCC段)。 - MFC库全局变量初始化(在.CRT$XCL段)。 - MFC程序全局变量初始化(在.CRT$XCU段)。 3. **theApp全局变量的作用**:引用[3]和[4],解释它是如何控制启动流程的。 - 在CWinApp构造函数中设置模块状态和线程状态。 - theApp初始化时调用InitInstance等函数。 4. **详细流程**: - 程序启动时,全局对象如theApp被构造。 - 在构造函数中,初始化关键状态(如线程ID、模块状态)。 - 然后调用InitInstance创建窗口等。 5. **为什么顺序重要**:引用[1]的例子,如果顺序错误,可能导致错误。 生成相关问题:基于主题,提出如: 1. 如何自定义MFC全局变量的初始化顺序? 2. MFC启动过程中如何处理依赖关系? 3.MFC中,全局变量的初始化失败会导致什么? 确保回答真实可靠:基于提供的引用,避免猜测。</think>### MFC应用程序启动时全局变量的初始化流程 在MFC(Microsoft Foundation Classes)应用程序启动过程中,全局变量的初始化是个关键步骤,它确保了程序的核心组件(如窗口、消息循环和库函数)能正确加载和执行。初始化流程严格遵循特定顺序,以避免因依赖关系导致的错误(如程序崩溃或未定义行为)。以下是基于MFC机制的详细流程分析,我将逐步解释每个阶段。 #### 1. **全局变量的初始化顺序** MFC应用程序启动时,全局变量根据其所在的编译段(section)进行初始化。这些段由编译器定义,初始化顺序由链接器控制: - **C++库全局变量**:位于`.CRT$XCC`段,最先初始化。这包括标准C++库(如`iostream`或`vector`)的全局对象,确保基础功能可用[^1]。 - **MFC库全局变量**:位于`.CRT$XCL`段,在C++库之后初始化。这包括MFC核心组件(如`CWinApp`或`CFrameWnd`相关的对象),为MFC框架提供支持[^1]。 - **应用程序全局变量**:位于`.CRT$XCU`段,最后初始化。这包括用户定义的全局对象,如`theApp`(MFC应用程序的核心全局变量)[^1]。 这个顺序至关重要,因为应用程序的全局变量(如`theApp`)可能依赖MFC或C++库中的函数和变量。如果顺序颠倒,例如应用程序变量先于库变量初始化,调用未初始化的库函数会导致运行时错误[^1]。 #### 2. **核心全局变量 `theApp` 的初始化** `theApp` 是用户定义的全局对象,通常继承自 `CWinApp`,它是MFC程序启动的入口点。初始化流程如下: - **构造阶段**:程序启动时,`theApp` 对象首先被构造(作为全局变量)。在 `CWinApp` 构造函数中,执行以下关键操作: - 获取当前模块状态(`AFX_MODULE_STATE`),用于管理应用程序的全局数据。 - 设置线程状态(`AFX_MODULE_THREAD_STATE`),存储当前线程信息(如线程ID和句柄)。 - 将 `this` 指针(指向 `theApp`)保存到模块状态中,使 `AfxGetApp()` 函数能返回 `theApp` 的引用[^4]。 例如: ```cpp CWinApp::CWinApp() { AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); pModuleState->m_pCurrentWinApp = this; // 保存 theApp 到全局状态 m_nThreadID = ::GetCurrentThreadId(); // 设置线程ID } ``` 此阶段确保 `theApp` 成为程序的核心控制器[^4]。 - **初始化调用**:构造完成后,`theApp` 调用其 `InitInstance()` 方法。此方法负责: - 创建主窗口(通过 `pFrame->Create()`)。 - 注册窗口类并显示窗口。 - 初始化消息循环[^3]。 如果 `InitInstance()` 失败,整个程序会终止[^3]。 #### 3. **依赖关系处理与错误预防** - **依赖管理**:由于应用程序全局变量(如用户定义的全局对象)在初始化时可能调用MFC库函数(如 `AfxGetApp()`),MFC通过严格的初始化顺序确保库函数已就绪。例如,在引用[1]的代码示例中,如果MFC库变量未初始化,调用 `MFC_function()` 会导致崩溃。 - **错误处理**:MFC使用断言(`ASSERT()`)在调试阶段检查初始化状态。如果全局变量初始化失败(如内存分配错误),程序会中止并输出错误信息[^4]。 #### 4. **完整启动流程总结** MFC应用程序的全局变量初始化是启动过程部分,整体流程如下: 1. 操作系统加载程序,初始化C运行时库。 2. 按段顺序初始化全局变量:C++库 → MFC库 → 应用程序变量(包括 `theApp`)。 3. `theApp` 构造并设置模块状态。 4. 调用 `theApp.InitInstance()` 创建窗口和消息循环。 5. 进入消息泵循环,程序运行[^2][^3]。 此流程确保了MFC框架的稳定启动,但也需注意:在编写全局变量时,应避免在构造函数中直接调用依赖库的功能,以防止顺序问题[^1]。 ### 相关问题 1. 如何自定义MFC全局变量的初始化顺序以避免依赖冲突? 2.MFC启动过程中,如果 `theApp` 初始化失败,程序如何处理? 3. MFC全局变量与多线程环境下的初始化有什么注意事项?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值