本文以孙鑫老师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)注册窗口类,那么系统就有了我们所编写的窗口过程函数的地址。
③

