Windows编程与MFC # 1

Windows是一个多任务的图形用户界面操作系统,学习和熟练掌握Windows应用程序的开发,首先需要了解Windows系统特点,理解Windows平台下应用程序的运行机制。
Microsoft的Windows系统是为PC机开发的GUI(Graphical User Interface)操作系统。它是一个多任务的操作系统。Windows应用程序具有统一的窗口和菜单界面。
由于Windows应用程序的窗口和菜单界面是统一的,所以对用户来说,Windows应用程序比传统的命令行式的应用系统更易于学习和使用。
Windows编程与MFC # 1_第1张图片
Windows编程与MFC # 1_第2张图片
Windows编程与MFC # 1_第3张图片

Windows编程与MFC # 1_第4张图片

  • 常用句柄类型及说明
    Windows编程与MFC # 1_第5张图片
    Windows编程与MFC # 1_第6张图片
    Windows编程与MFC # 1_第7张图片
    Windows编程与MFC # 1_第8张图片
    Windows编程与MFC # 1_第9张图片
    Windows编程与MFC # 1_第10张图片
    Windows编程与MFC # 1_第11张图片
    Windows编程与MFC # 1_第12张图片
    Windows编程与MFC # 1_第13张图片
    Windows编程与MFC # 1_第14张图片
    Windows编程与MFC # 1_第15张图片
    Windows编程与MFC # 1_第16张图片
    Windows编程与MFC # 1_第17张图片
    Windows编程与MFC # 1_第18张图片
    MFC类库包括用来开发C++应用程序和Windows应用程序的一组类,这些类用来表示窗口、对话框、设备上下文、公共GDI对象如画笔、调色板、控制框和其它标准的Windows部件,封装了大部分的Windows API函数

Windows编程与MFC # 1_第19张图片

#include   
int  WINAPI   WinMain(HINSTANCE hInstance,HINSTANCE   hPrevInstance,PSTR szCmdLine,int  iCmdShow )  
{  
    MessageBox(NULL, TEXT("你好, 欢迎来到VC之路"),TEXT("欢迎"),0);  
    return 0;  
} 

C语言编程必须有且只有一个主函数main()。Windows程序则有一个主函数称为WinMain(), 该函数为Windows应用程序的入口点,它的名字一定要是WinMain。
第一个参数:应用程序的当前实例句柄。
第二个参数:应用程序的前一个实例句柄,别管它,对于Win32位而言,它一般是NULL.
第三个参数:指向任何传给程序的命令行参数。PSTR代表"指向字符串的指针"。
第四个参数:它告诉应用程序如何初始化窗口,如最大化,最小化等状态。

Windows编程与MFC # 1_第20张图片
WinMain()所起的作用:初始化,展示,销毁应用程序等。
MessageBox(),是一个很常用的API。用于以对话框的形式来输出信息。

Windows编程与MFC # 1_第21张图片

#include 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);    //窗口函数声明
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	HWND hwnd;                                                           //窗口类句柄
	MSG Msg;                                                                //消息结构变量
	WNDCLASS wndclass;                                          //窗口类结构变量
	char lpszClassName[]="窗口";	                                //窗口类名
	char lpszTitle[]="这是一个基本的Windows程序"; 	//标题栏
	//定义窗口类的属性
	wndclass.style=CS_HREDRAW|CS_VREDRAW;   //改变窗口大小则重画
	wndclass.lpfnWndProc=WndProc; 		//窗口函数为WndProc
	wndclass.cbClsExtra=0;			//窗口类无扩展
	wndclass.cbWndExtra=0;			//窗口示例无扩展
	wndclass.hInstance=hInstance;		//注册窗口类实例句柄
	wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION);           //应用图标
	wndclass.hCursor=LoadCursor(NULL, IDC_ARROW);	//箭头光标
	wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  //白色背景 
	wndclass.lpszMenuName=NULL;	                                //无菜单
	wndclass.lpszClassName=lpszClassName;		//窗口类名为“窗口”
	if(!RegisterClass(&wndclass))                                             //注册窗口类
		return FALSE; 
	//创建窗口
	hwnd=CreateWindow(     lpszClassName,		//窗口类名
			          lpszTitle,			//窗口名
			          WS_OVERLAPPEDWINDOW,	//重叠式窗口
			          CW_USEDEFAULT, 		//左上角屏幕坐标默认值
			          CW_USEDEFAULT,	
                                                          CW_USEDEFAULT, 		//窗口宽度和高度默认值
			          CW_USEDEFAULT,				
			          NULL, 			//无父窗口
			          NULL, 			//无主菜单
			          hInstance,	                                //创建此窗口的实例句柄
			          NULL);		                //无创建参数
		ShowWindow(hwnd, nShowCmd);		//显示窗口
		UpdateWindow(hwnd);			//更新窗口客户区
		while(GetMessage(&Msg, NULL, 0, 0))                //消息循环
		{
			TranslateMessage(&Msg);		//消息转换
			DispatchMessage(&Msg);	                //派送消息到窗口函数
		}
		return Msg.wParam;			//返回退出值
}

//窗口函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	//根据消息值转向不同的处理
	switch(message)
	 {
	       case WM_PAINT:	                                        //重绘窗口客户区消息处理
		        HDC hdc;                                               //设备描述表句柄
		        PAINTSTRUCT ps;	                       //绘图信息结构变量
		        hdc = BeginPaint(hwnd,&ps);	       //获取要重绘设备描述表句柄
		        TextOut(hdc,10,10,"这是一个窗口",12);	//输出文本
		        EndPaint(hwnd,&ps);	                       //结束要绘制的窗口
		        break;
	       case WM_DESTROY:	                                      //撤销窗口消息处理
		        PostQuitMessage(0);	                      //产生退出消息WM_QUIT
		        break;
	       default: 		                                     //默认窗口函数
		        return DefWindowProc(hwnd, message, wParam, lParam); 
	}
	return 0;
}

Windows编程与MFC # 1_第22张图片
如果出现
error C2440: “=”: 无法从“char [5]”转换为“LPCWSTR”
一般出现这种BUG 的,是由于字符集的问题。在vs2010中有两个字符集,Unicode 和 Muti-bye。
LPCTSTR在Multi-byte Character方式下与const char等价,在Unicode方式下与const tchar等价。所以在Unicode方式下对其赋值像下面这样:
LPCTSTR location = _T(“Software//”); //加_T进行转化。

Bug修改方法:
中文版:
项目->项目属性->配置属性->常规->项目默认值->字符集
注意:
原来是Unicode (安装时的默认值)
改为使用多字符集 。


Windows编程与MFC # 1_第23张图片
① 注册窗口类
第一步:定义一个窗口类结构数据变量
第二步:给相关的注册项赋值
第三步:注册这个窗口类

ATOM RegisterClass( CONST WNDCLASS *lpWndClass);// 指向窗口类结构数据的指针
函数的返回类型是ATOM,这是一个Windows定义的数据类型,相当于C语言中的unsigned short。如果注册成功,将返回一个唯一的类标识值。否则返回0。

②建立和显示窗口
HWND CreateWindow(
LPCTSTR lpClassName, // 已经注册了的窗口类的名称
LPCTSTR lpWindowName, // 窗口名称,标题栏上显示的
DWORD dwStyle, // 窗口的样式
int x, // 窗口左上角的横坐标
int y, // 窗口左上角的纵坐标
int nWidth, // 窗口的宽度
int nHeight, // 窗口的高度
HWND hWndParent, // 父窗口
HMENU hMenu, // 菜单或子窗口标识
HANDLE hInstance, // 模块实例句柄
LPVOID lpParam // 创建窗口时的参数
);

BOOL ShowWindow(
HWND hWnd, // 窗口句柄
int nCmdShow // 执行显示的状态
);

函数GetMessage
BOOL GetMessage(
LPMSG lpMsg, // 接收消息的变量地址
HWND hWnd, // 接收消息的窗口
UINT wMsgFilterMin, // 消息的下限
UINT wMsgFilterMax // 消息的上限
);
GetMessage函数负责将消息接收。当接收到的消息是WM_QUIT时,返回0,结束消息循环。

函数TranslateMessage
BOOL TranslateMessage(CONST MSG *lpMsg //消息结构变量的地址
);
说明:负责将虚拟键消息转换成字符消息。值得注意的是该函数并不是修改参数lpMsg 所指定的消息,而是视情况产生一个新的消息。

函数DispatchMessage
LONG DispatchMessage(CONST MSG *lpmsg //消息结构变量的地址
);
说明:该函数负责进一步将消息传递的指定窗口(子窗口或对象)的窗口函数。

窗口函数的格式
LRESULT CALLBACK WindowProc(
HWND hwnd, // 窗口句柄
UINT uMsg, // 消息标识
WPARAM wParam, // 附加参数1
LPARAM lParam // 附加参数2
);
函数返回值取决于所处理的消息。

窗口函数将消息通过参数message带入,我们的任务就是处理这些消息。用switch-case分支结构分拣这些消息,挑选出我们需要处理的消息,写出相应的处理代码,其余的交给函数DefWindowProc()。

函数DefWindowProc
LRESULT DefWindowProc(
HWND hwnd, // 窗口句柄
UINT uMsg, // 消息标识
WPARAM wParam, // 附加参数1
LPARAM lParam // 附加参数2
);

处理消息的原则是凡是窗口函数不处理或处理不了的消息,都必须传送到DefWindowProc,其返回值也是取决于所处理的消息。

消息循环中函数DispatchMessage的返回值,就是来自窗口函数的返回值。

Windows编程与MFC # 1_第24张图片
为了解决这些问题,微软使用typedef关键字,为很多常用的C类型均定义了别名,这样一来,要解决源代码移植问题,只需在目标平台上定义相同的一套类型别名,即可解决大部分问题。

  • WIN32API常见API的数据类型
    Windows编程与MFC # 1_第25张图片

Windows编程与MFC # 1_第26张图片
Windows编程与MFC # 1_第27张图片
Windows编程与MFC # 1_第28张图片
Windows编程与MFC # 1_第29张图片
typedef struct tagMSG {
HWND hwnd; //消息发向的窗口句柄
UINT message; //消息标识符
WPARAM wParam;
//16位的消息参数,值因消息而异
LPARAM lParam;
//32位的消息参数,值因消息而异
DWORD time; //消息放入消息队列的时间
POINT pt; //消息放入消息队列的鼠标位置
} MSG;
说明:WPARAM含义和数值因消息不同而不同
比如:键盘消息和鼠标消息所对应的WPARAM消息所代表的消息是不同的。

hwnd是一个窗口句柄,用于标识消息发向的窗口。

time用于保存消息放进消息队列的时间。

pt用于保存将消息放入消息队列时的鼠标位置。

message是消息标识符,它是一个32位的无符号整数。Windows中的每条消息都有一个对应的消息标识符,这些标识符是在windows.h中定义的。

Windows编程与MFC # 1_第30张图片
Windows编程与MFC # 1_第31张图片
加速键类似组合键

Windows编程与MFC # 1_第32张图片
控件通知消息的格式有三种:
(1)仿窗口消息的格式,如滚动控件消息WM_HSCROLL。
(2)仿命令消息的格式,如用户修改了编辑控件中的文本后,编辑控件向父窗口发送的WM_COMMAND通知消息,该消息包含了控件通知消息EN_CHANGE。
(3)单独控件消息的格式,如消息WM_NOTIFY。

主窗口显示出来了,WinMain就开始处理消息了,怎么做的呢?
Windows为每个正在运行的应用程序都保持一个消息队列。
当你按下鼠标或者键盘时,Windows并不是把这个输入事件直接送给应用程序,而是将输入的事件先翻译成一个消息,然后把这个消息放入到这个应用程序的消息队列中去。
应用程序又是怎么来接收这个消息呢?这就要说到消息循环了。

应用程序的WinMain函数通过执行一段代码从它的消息队列中来检索Windows送往它的消息。然后WinMain就把这些消息分配给相应的窗口函数以便处理它们,这段代码是一段循环代码,故称为“消息循环”。
MSG Msg; //定义消息名
while (GetMessage (&Msg, NULL, 0, 0))
{
TranslateMessage (&Msg) ; //翻译消息
DispatchMessage (&Msg) ; //分发消息
}
return msg.wParam ;

Windows编程与MFC # 1_第33张图片
窗口函数 WndProc()
在Windows中,应用程序通过要求Windows完成指定操作,而承担这项通信任务的API函数就是Windows的相应窗口函数WndProc。
在DOS里,程序能直接控制事件的发生顺序;而在Windows里,应用程序不直接调用任何窗口函数,而是等待Windows调用窗口函数,请求完成任务或返回信息。

回调函数
为保证Windows调用这个窗口函数,这个函数必须先向Windows登记,然后在Windows实施相应操作时回调,所以窗口函数又称为回调函数
WndProc是一个主回调函数,Windows应用程序至少有一个回调函数。下面语句即向Windows登记了窗口函数:
wndclass.lpfnWndProc=WndProc;
// lpfnWndProc是指向窗口过程函数的指针

你可能感兴趣的:(Windows编程)