本文以孙鑫老师VC++教程中的程序为基础,详细讲解了Windows程序内部运行机制,相信可以帮助大家更好的理解Windows程序运行原理及相应的VC++程序设计。具体内容如下:
创建一个Win32应用程序步骤:
1、编写WinMain函数;
2、创建窗口(步骤如下):
a、设计(一个)窗口类(WNDCLASS)
b、注册(该)窗口类。
c、创建窗口。
d、显示并更新窗口。
3、编写消息循环。
4、编写窗口过程函数。
//WinMain.cpp #include <windows.h> #include <stdio.h> LRESULT CALLBACK WinAzeProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { //设计一个窗口类 WNDCLASS wndcls; wndcls.cbClsExtra = 0; wndcls.cbWndExtra = 0; wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wndcls.hCursor = LoadCursor(NULL, IDC_CROSS); wndcls.hIcon = LoadIcon(NULL, IDI_ERROR); wndcls.hInstance = hInstance; //应用程序实例句柄由WinMain函数传进来 wndcls.lpfnWndProc = WinAzeProc; wndcls.lpszClassName = "aze_003"; wndcls.lpszMenuName = NULL; wndcls.style = CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); //注册窗口类 //创建窗口,定义一个变量用来保存成功创建后返回的句柄 HWND hwnd; hwnd = CreateWindow("aze_003", "first Application", WS_OVERLAPPEDWINDOW, 0, 0, 600, 500, NULL, NULL,hInstance, NULL); ShowWindow(hwnd, SW_SHOWNORMAL); //显示窗口 UpdateWindow(hwnd); //刷新窗口 //定义消息结构体,开始消息循环 MSG msg; while( GetMessage(&msg, NULL, 0, 0) ) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //编写窗口过程函数 LRESULT CALLBACK WinAzeProc( 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 code is %d", wParam); MessageBox(hwnd, szChar, "char", 0); break; case WM_LBUTTONDOWN: MessageBox(hwnd, "mouse clicked", "message", 0); HDC hdc; hdc = GetDC(hwnd); //不能在响应WM_PAINT消息时调用 TextOut( hdc, 0, 50, "程序员之家!",strlen("程序员之家!") ); ReleaseDC(hwnd, hdc); break; case WM_PAINT: HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hwnd, &ps); //BeginPaint只能在响应WM_PAINT消息是调用 TextOut(hDC, 0, 0, "http://www.sunxin.org", strlen("http://www.sunxin.org")); EndPaint(hwnd, &ps); break; case WM_CLOSE: if( IDYES == MessageBox(hwnd, "是否真的退出?", "message", MB_YESNO) ) { DestroyWindow(hwnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }</div>
程序运行后显示界面如下:
窗口分为客户区(是窗口的一部分)与非客户区。
标题栏、菜单栏、系统菜单、最小(大)化框、可调边框统称为窗口的非客户区,由Windows系统管理;应用程序主要管理客户区的外观及操作(显示文字、绘制图形)。
对话框、消息框也是一种窗口;对话框上还包括许多子窗口:按钮、单选按钮、复选框、组狂、文本编辑框等。
2、窗口与句柄:
在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的;要对某个窗口进行操作,就必须要得到这个窗口的句柄。
句柄是Windows程序中一个重要的概念(图标句柄(HICON)、光标句柄(HCURSOR)、画刷句柄(HBRUSH))。
3、消息与消息队列:
Windows程序设计模式是一种事件驱动方式的程序设计模式,主要是基于消息的。(当系统感知到一事件时(如点击鼠标),系统会将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。在这个处理过程中,操作系统也会给应用程序“发送消息”。“发送消息”:实际指:操作系统调用程序中一个负责处理消息的窗口过程函数)
(1)消息:Windows中,消息由MSG结构体表示,如下:
//The MSG structure contains message information from a thread's message queue. typedef struct tagMSG { HWND hwnd; //消息所属的窗口,消息都是与窗口相关联的 UINT message; //the message identifier WPARAM wParam; //指定消息的附加消息 LPARAM lParam; //指定消息的附加消息 DWORD time; //消息投递到队列中的时间 POINT pt; //鼠标的当前位置 } MSG, *PMSG;</div>
Windows中,消息是由一个个数值表示的;Windows将消息对应的数值定义为WM_XXX宏(WM:Window Message)的形式,XXX对应某种消息的英文拼写的大写形式。如:WM_LBUTTONDOWN:鼠标左键按下消息、WM_KEYDOWN:键盘按下消息、WM_CHAR:字符消息···
(2)消息队列:每一个Windows应用程序开始执行后,系统都会为改程序创建一个消息队列,这个消息队列用来存放改程序创建的窗口的消息。
(3)进队消息 与 不进队消息:
进队的消息将由系统放入到应用程序的消息队列中,然后由应用程序取出并发送;
不进队消息在系统调用窗口过程时,直接发送给窗口;
两者最终都是有系统调用窗口过程函数对消息进行处理。
4、WinMain函数
(一)MSDN上的WinMain函数定义如下(备有详尽的注释):
//The WinMain function is called by the system as the initial entry point for a Windows-based application. int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance当前窗口句柄 HINSTANCE hPrevInstance, // handle to previous instance前一个打开的窗口句柄 LPSTR lpCmdLine, // command line 指定传递给应用程序的*命令行*参数 int nCmdShow // show state 指定窗口应该如何显示,如:最大(小)化、隐藏等 );</div>
(二)窗口类的结构体的定义:
(1)本文程序中对应代码如下:
typedef struct _WNDCLASS { UINT style; //指定*这一类型*窗口的样式,如:CS_HREDRAW、CS_VREDRAW、CS_NOCLOSE、CS_DBLCLKS WNDPROC lpfnWndProc; //函数指针,指向窗口过程函数(窗口过程函数是一回调函数) int cbClsExtra; //一般为0 int cbWndExtra; //同上 HINSTANCE hInstance; //指定包含窗口过程的程序的实例句柄 HICON hIcon; //指定窗口类的图标句柄 HCURSOR hCursor; //指定窗口类的光标句柄 HBRUSH hbrBackground; //指定窗口类的背景画刷句柄;当窗口发生重绘值,系统使用这里指定的画刷来查处窗口的背景 LPCTSTR lpszMenuName; //指定菜单资源的名字 **菜单并不是一个窗口** LPCTSTR lpszClassName; //指定窗口类的名字 } WNDCLASS, *PWNDCLASS;</div>
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时有另一方调用的,用于该事件或条件进行响应。
回调函数的实现机制是:
①定义一个回调函数。
②提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者。
③当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
针对Windows的消息处理机制,窗口过程函数被调用的过程如下:
①在设计窗口类的时候,将窗口过程函数的地址赋值给lpfnWndProc成员变量;
②调用RegisterClass(&wndclass)注册窗口类,那么系统就有了我们所编写的窗口过程函数的地址。
③