【MFC】第一个窗口程序(2)

Windows C窗口程序

也称“SDK编程”,即调用 Windows 提供的API接口(C),完成窗口程序的设计,API接口可以理解为一些C的函数和数据类型(结构体、枚举)。

难点1:

突然冒出很多“新”的数据类型,DWORD 、LPSTR 、LRESULT等等

难点2:

句柄的概念,应用程序实例句柄、窗口句柄、画刷光标句柄、文件句柄等等

难点3:

消息队列、消息处理与程序流程。

先写一个最简单的SDK窗口程序(VS2012平台):

步骤1:

创建工程,选择《Win32项目》(不是控制台项目)

【MFC】第一个窗口程序(2)_第1张图片

 步骤2:

一步一步点下去,在《应用程序设置》页面,把 空项目 勾上,空白项目压力最小。

【MFC】第一个窗口程序(2)_第2张图片

步骤3:

添加一个CPP文件,编写代码:

【MFC】第一个窗口程序(2)_第3张图片

代码如下:

#include 
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
	case WM_DESTROY:   
	case WM_CLOSE:
		::PostQuitMessage(0);
		break;	 
	default:
		return  ::DefWindowProc(hwnd,message,wParam,lParam);
	}
	return 0;

}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	WNDCLASS wc;
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
//	wc.hbrBackground=NULL;
	wc.hbrBackground=(HBRUSH)::GetStockObject(GRAY_BRUSH);
//	wc.hCursor=NULL;
	wc.hCursor=::LoadCursor(NULL,IDC_CROSS);
	wc.hIcon=NULL;
	wc.hInstance=hInstance;
	wc.lpfnWndProc=WndProc;
	wc.lpszClassName="Test";
	wc.lpszMenuName=NULL;
	wc.style=CS_VREDRAW | CS_HREDRAW;

	::RegisterClass(&wc);
	HWND hwnd = ::CreateWindow("Test","First Windows Appliation",WS_OVERLAPPEDWINDOW,0,0,800,600,NULL,NULL,hInstance,NULL);
	::ShowWindow(hwnd,nCmdShow);
	::UpdateWindow(hwnd);

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

}

 1、WinMain 是程序的入口,由操作系统调用,返回 int 值供操作系统了解程序运行的结果(是否异常),这与控制台的main 函数类似;

2、函数调用的规则:函数调用的时候,需要把参数入栈,调用完毕也需要回收栈的空间,多个参数则有从右到左或者相反的方向。__stdcall 和 __cdec 都是从右到左,其中__cdec是C和C++程序的缺省调用方式,特点是 调用函数 负责栈的管理。__stdcall 则是由被调函数完成栈的管理(回收)。

3、WINAPI 、CALLBACK 都是__stdcall

【MFC】第一个窗口程序(2)_第4张图片

 其实这点区别不重要,关键是 回调函数 ,普通的函数调用方默认等待被调函数的返回,有些情况下肯定是不行的,比如消息处理函数:如果“消息处理” 不能  “并行” 操作,那么可能消息堵塞!

所以,有些函数应该设计成类似 “线程” 的非等待类型函数。这时候主调函数回收栈的方式就不能接收了,因为主调函数不等待被调函数结束!

然而,上面的都不重要!指定函数为WINAPI 基本上不会出错

4、四个参数,两个句柄 (HINSTANCE),句柄其实就是一个32位的无符号整数,Windows管理文件、内存、GDI(画笔、画刷等待绘图工具)、图标、光标、菜单等待,各种各样的资源。为了管理方便,给每个资源进行编号(就像身份证)就可以理解了,但是。。。一个无符号整数是很难理解的,所以用typedef 给 unsigned int 搞几个别名吧!这样就好理解!

Windows下出现的各种 “新” 数据类型中,很多都是这样的操作!

5、第一个参数,操作系统分配给应用程序的句柄(身份ID),后面属于该程序的窗口等等,都可以利用它来表明身份,第二个参数已经被弃用(程序运行多个副本),第三个参数是命令行,运行程序的同时可以加入命令行参数(类似ping ******),第四个参数就是窗口的显示方式,最大化、隐藏、最小化等等

6、WinMain的基本流程是,定义一个描述窗口特征的结构体(WNDCLASS),填写结构体的分量值(其中最重要的填入窗口的消息处理函数),注册这个窗口类(此类并非面向对象的类),根据注册的窗口类名称创建窗口、显示窗口,然后进入一个类似“死”循环的消息处理。最后在获取到主窗口销毁消息后退出程序。

7、窗口函数:LRESULT也是一个32位无符号整数,返回消息处理结果。四个参数,第一个是窗口句柄,注册窗口类绑定了窗口函数,注册的窗口类是可以创建多个窗口的,所以消息是发给哪个窗口的,必须区分。第二个参数是消息的类型,枚举类型(其实也是int);第三和第四个参数是附加信息,比如鼠标点击消息需要附加鼠标位置、按键信息等等。

窗口函数肯定是一个switch 结构,对不同消息进行不同入口处理,这里其实是窗口程序设计的重点

8、WinMain消息循环中,GetMessage的第二个参数必须设置成NULL (所有窗口),否则程序无法通过关闭窗口进行退出。(窗口关闭,销毁窗口,回收窗口句柄,只捕获该窗口消息则无法获取后续的WM_QUIT消息)。

你可能感兴趣的:(MFC,mfc,c++)