首先,如果编写一个windows应用程序,最直接的方法是使用MFC,因为MFC已经为我们处理了很多繁杂的过程,若不采用MFC,则通常的做法是调用windows API函数实现。如经过以下步骤,可以创建一个简单的窗口。
- 注册窗口
HWND h_Wnd; //保存创建窗口的句柄 WNDCLASS w_Class; MSG msg; //用以消息循环的MSG结构体 w_Class.cbClsExtra = 0; w_Class.cbWndExtra = 0; w_Class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); w_Class.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW); w_Class.hIcon = (HICON)LoadIcon(NULL, IDI_APPLICATION); w_Class.hInstance = hInstance; w_Class.lpszClassName = "Application"; w_Class.lpszMenuName = NULL; w_Class.style = 0; w_Class.lpfnWndProc = WndProc; RegisterClass(&w_Class);
- 创建窗口
h_Wnd = CreateWindow("Application", "MyWindow", WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, hInstance, NULL);
- 显示窗口
ShowWindow(h_Wnd, nShowCmd);
- 更新窗口
UpdateWindow(h_Wnd);
- 消息循环
while (GetMessage(&msg, h_Wnd, NULL, NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); }
- 消息处理
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_LBUTTONDOWN: { MessageBeep(0); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,message,wParam,lParam); } return 0; }
当然,以上代码必须加入头文件#include <Windows.h>,以上代码只简单展示了窗口的创建过程以及对鼠标左键按下的消息处理的过程(发出windows嘣嘣声)。
Windows应用程序的一个特点是在程序启动并创建了程序窗口后,就进入了一个等待状态(上面代码的while循环),直到受到某种刺激(消息)之后,如鼠标单击,键盘按下等,上面代码只有鼠标单击和关闭,程序才会脱离等待状态对这个消息进行处理(上面代码的信息处理函数WndProc),处理完成后接着等待下一个信息,以此类推。这些能够触发计算机程序作出相应的刺激或者消息称为事件。
为了描述事件的各种信息,windows定义了一个结构,上面代码的MSG msg,这个结构就叫做消息。
typedef struct tagMSG { HWND hwnd; //产生消息的窗口句柄 UINT message; //消息的标识码 WPARAM wParam;// 消息的附加信息 LPARAM lParam; //消息的附加信息 DWORD time; //消息进入消息队列的时刻 POINT pt;//发送该消息时光标的位置 } MSG;
这样,当计算机发生某件事,windows会把该事件的相关信息添加到该MSG结构体的各个域中,并把这个消息送达到应用程序,而应用程序则根据消息里的结构变量的值来确定如何处理该消息。Windows已经把绝大多数事件的消息事先进行了定义,并定义了对消息的标示码。如WM_LBUTTONDOWN,WM_LBUTTONUP等待。
系统为每个应用程序都建立了一个叫做消息队列的存储空间,在程序运行过程中发生某事件,windows就会把这个事件所对应的消息送入消息队列中等待使用。而应用程序可以通过使用windows提供的API(GetMessage())从消息队列中获取消息,并利用GetMessage()的返回值(当获得一个消息时返回TRUE,否则返回FALSE)来形成一个循环,从而可以不断地从消息队列中获取消息,一旦获取一个消息,就发送给系统。这个循环就叫消息循环。如上面代码的while循环部分。
当函数DispatchMessage()把消息拍送给系统后,系统会根据消息中的hWnd找到应该接受消息的窗口,并根据窗口提供的信息,以消息为参数来调用一个用户编写的叫做“窗口函数”的函数,上面代码中的WndProc(),在该函数里用户可以按照自己的方式处理各种消息。处理完成后,只要该消息不是终止应用程序的消息,则会立即返回消息循环,等待下一个消息。Windows应用程序就这样周而复始的循环,直至用户发出结束应用程序的消息(上面代码的WM_DESTROY)。
正是windows应用程序必须接受一个消息才会启动某种操作,因此人们常说windows应用程序的运行是消息驱动或者事件驱动的。
Windows消息从输出路径来看,可以分为两类:一类是先把消息送到消息队列,然后由应用程序的消息循环通过函数DispatchMessage()发送给窗口,这类消息叫队列消息,鼠标和键盘都是队列消息;另一类是不经过消息队列而直到窗口的消息,这类消息叫非队列消息,系统事件产生的消息一般为非队列消息。
随便提一下上面消息循环的TranslateMessage(),该函数是将消息(如鼠标消息)转换为或者“翻译成”可以被系统识别的消息。
消息的传递过程如图1-1。
图1-1 windows消息传递过程
此图最右边方向箭头画错了,应该是从应用程序消息处理到消息循环(反过来)