这一系列的MFC笔记,来源于孙鑫老师的VC++视频教程,如果大家有时间,可以在网上参考。
lesson1:浅谈Windows程序内部运行机制
1.Windows 消息响应机制
Windows程序不同于传统的dos方式的设计方法,它一种事件驱动的,是基于消息的,操作系统将用户的需要包装成消息,然后将消息投递到消息队列中,最后应用程序从消息队列中取走消息并进行响应。
Windows应用程序,操作系统,计算机硬件之间的相互关系:
箭头①表示操作系统能够操作输出设备,箭头③表示应用程序可以通知操作系统执行某个具体的动作,如操作系统能够控制声卡发出声音,但它并不知道应该何时发出何种声音,需要应用程序告诉操作系统该发出什么样的声音。箭头②表示操作系统能够感知输入设备状态的变换,箭头④表示操作系统能够将输入设备的变化上传给应用程序。如用户在某个程序活动时按了一下键盘,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何作出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件作出反应。因此操作系统相当于是一个中介。
那么,应用程序是如何通知操作系统执行某个功能的呢?在应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application ProgrammingInterface),简称Windows API。
操作系统是怎样将感知到的事件传递给应用程序的呢?这是通过消息机制(Message)来实现的。操作系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用程序,参看MSDN。每一个应用程序都用一个消息队列,它是一个先进先出的缓冲队列,每一个元素都是一个消息。应用程序取得消息得知用户的操作。至于消息的处理,是通过消息响应程序处理的,操作系统自动调用消息响应函数,但消息的响应方式,即这个函数得自己编写。这个可以是用Windows自己默认的处理函数,和可以自己编写处理函数。MSG结构定义如下:
typedef struct tagMSG {
HWND hwnd; //窗口句柄,指定与消息相关的窗口
UINT message; //用无符号整型指定消息类型,Windows的消息都是提前用整数表示好的
WPARAM wParam; //指定消息的附加信息
LPARAM lParam; //指定消息的附加信息
DWORD time; //指定消息投递的时间
POINT pt; //指定消息投递时光标的位置
} MSG;
2. 创建一个完整的窗口需要经过下面四个操作步骤:
【1 设计一个窗口类】:窗口背景,鼠标,光标,窗口最大化,最小化,窗口名称,窗口设计时,有相应的窗口类,我们只需要给成员变量赋相应的值,达到我们需要的结果;
【2 注册窗口类】:向操作系统声明,有这样一种设计的窗口;
【3 创建窗口】:产生窗口;
【4 显示及更新窗口】:窗口发生变化时(移动),重新绘制窗口。
下面是程序代码,并附有完整的注释。
#include<windows.h> //windows的头文件 #include<stdio.h> //C语言的头文件 LRESULTCALLBACK WinSunProc( //消息响应函数,函数原型的申明,以被后面调用 HWND hwnd, <span style="white-space:pre"> </span>// handle to window UINT uMsg, <span style="white-space:pre"> </span>// message identifier WPARAM wParam, <span style="white-space:pre"> </span>// first message parameter LPARAM lParam <span style="white-space:pre"> </span>// second message parameter ); intWINAPI WinMain( //Windows程序入口点函数 WinMain函数 HINSTANCE hInstance, // handle to current instance 当前运行实例句柄 HINSTANCE hPrevInstance, // handle to previous instance 先前一实例句柄(同一个应用程序之间) LPSTR lpCmdLine, // command line 命令行参数 int nCmdShow // show state 状态显示,指定程序窗口如何显示(最大化,最小化,隐藏等) ) { WNDCLASS wndcls; //【第一步 设计一个窗口类】</span> wndcls.cbClsExtra=0; //额外的类的附加内存空间,附加字节数,通常设为0 wndcls.cbWndExtra=0; //窗口的附加内存空间,附加字节数 wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //窗口背景 HBRUSH是数据类型强制转换 wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); //光标 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //图标 wndcls.hInstance=hInstance; //应用程序的实例号 wndcls.lpfnWndProc=WinSunProc; //窗口过程函数,就是消息响应函数。操作系统自动调用这个函数,但消息响应函数得自己写收到消息时的处理动作 wndcls.lpszClassName="Weixin2003"; //类名 wndcls.lpszMenuName=NULL; //菜单名字(没有菜单) wndcls.style=CS_HREDRAW |CS_VREDRAW; //窗口刷新类型是水平和垂直重画,移动窗口时发生(水平/垂直坐标变换), //如果没有重绘,窗口移动时,上面的图片或文字不发生变化 RegisterClass(&wndcls); //【第二部 注册窗口类】</span>以被调用 HWND hwnd; //【第三部 创建窗口】</span>定义句柄 hwnd=CreateWindow("Weixin2003","北京维新科学技术培训中心",WS_OVERLAPPEDWINDOW, 0,0,600,400,NULL,NULL,hInstance,NULL); //(类名,窗口名字,窗口类型,窗口坐标x,y和窗口大小高、宽, //副窗口,菜单,实例的句柄,窗口创建的数据) ShowWindow(hwnd,SW_SHOWNORMAL); //【第四部 显示及更新窗口】</span> UpdateWindow(hwnd); MSG msg; //消息循环 while(GetMessage(&msg,NULL,0,0)) //获得消息,返回值为真,为假程序退出所有消息都获取(消息信息,窗口句柄指定哪个窗口的消息<span style="font-family: Arial, Helvetica, sans-serif;">null表示获取所有消息,</span> //最后两参数为消息过滤,最小消息值(第一个鼠标消息或键盘消息),最大消息值,当两个为0 ,表示所有消息) { TranslateMessage(&msg); //转换消息并投递到消息队列中 DispatchMessage(&msg); //将消息从消息队列中取出并传递给窗口的过程函数(回调函数CALLBACK) } //可以理解为它把消息给操作系统,然后操作系统做出相应动作,动作是我们编写的CALLBACK函数 return 0; } LRESULTCALLBACK WinSunProc( //编写的响应消息的回调函数CALLBACK函数 HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { switch(uMsg) { case WM_CHAR: //输入字符 char szChar[20]; //定义字符数组 sprintf(szChar,"char is%d",wParam); //格式化文本到内存buffer中 MessageBox(hwnd,szChar,"weixin",0); //弹出窗口内容 文本内容szChar 标题weixin 窗口类型0 break; case WM_LBUTTONDOWN: //左单击鼠标 MessageBox(hwnd,"mouseclicked","weixin",0); //弹出消息框 HDC hdc; //定义HDC结构体 ,设备上下文句柄,device contest句柄,DC帮助我们与显示程序交互 hdc=GetDC(hwnd); TextOut(hdc,0,50,"计算机编程语言培训",strlen("计算机编程语言培训")); //在0,50输出内容 ReleaseDC(hwnd,hdc); //释放 break; case WM_PAINT: //窗口重绘 HDC hDC //定义 PAINTSTRUCT ps; //定义结构体 hDC=BeginPaint(hwnd,&ps); //开始,这对函数只能在WM_PAINT中使用 TextOut(hDC,0,0,"维新培训",strlen("维新培训")); EndPaint(hwnd,&ps); //结束 break; case WM_CLOSE: //关闭窗口 if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO)) //判断是否结束 { DestroyWindow(hwnd); //销毁窗口,此函数Y会传递一个消息位WM_DESTORY } //即下一个case的地方 break; case WM_DESTROY: //销毁窗口 PostQuitMessage(0); //退出 break; default: //返回缺省的窗口处理方式 returnDefWindowProc(hwnd,uMsg,wParam,lParam); } return 0; }
程序思路很简洁,WinMain为主函数,主函数进行设计、注册、产生和重绘窗口。在设计窗口的时候指定了窗口的消息响应函数WinSunProc,因此每一个消息都用WinSunProc函数进行处理。
下面是附加的参考文献:
1. 消息函数 typedef structtagMSG
参考 http://blog.ifeng.com/article/2683896.html
2. 窗口建立函数 int WINAPI WinMain
参考 http://blog.csdn.net/seawave/article/details/1338879
程序运行截图: