======写在前面=====
这一系列的MFC笔记,主要参考了孙鑫老师的《VC++深入详解》和毛星云老师的《Windows游戏编程之从零开始》。
前面来源于孙鑫老师的VC++视频教程,如果大家有时间,可以在网上下载学习参考。
后面参考了毛星云老师的著作,这里也给上毛星云作者的博客地址:http://blog.csdn.net/poem_qianmo?viewmode=contents
============================
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
程序运行截图: