您的位置:首页 > 其它

MFC Windows应用程序的基本运行机制与HelloWin程序详细解

2008-05-14 10:16 501 查看
Windows应用程序的基本运行机制与HelloWin程序详细解
  总的来说最基本的Windows应用程序的运行执行顺序总是以如下的基本顺序执行的。
顺序结构:
调用 WinMain函数开始执行 -- à 定义窗口类 -- à 初始化窗口类 --- à 窗口的实例化 -- à 通过消息循环获取消息并将消息发送 给消息处理函数做出相应的操作
  由于windows应用程序运行的逻辑结构特殊所以代码的详细解释笔者就不把程序于叙述分开了了,这样有利于阅读与分析。

程序运行预览图
  下载该程序:点击这里下载(82K, winzip压缩文件)
  分析代码如下:
// 程序作者 : 管宁
// 站点 :www.cndev-lab.com
// 所有稿件均有版权 , 如要转载 , 请务必注明出处和作者

#include < windows.h>
# pragma comment( lib,"winmm.lib") // 为了要播放声音,必须导入这个库

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
/*
HINSTANCE 类型的含义为实例句柄。
hInstance 事实上就是当前应用程序自身的标识代号 ,代号通常都是一个 32位整数。
hPrevInstance 与过去的 16位应用程序有关系,表示指向前一个实例的句柄。

PSTR 类型的含义是指向以 /0结尾的字符串指针。
szCmdLine 前面的 sz同样是表示指向以 /0结尾的字符串指针,这个对象用于保存命令行。

最后 iCmdShow是一个整型数据,标记了程序最初的显示状态。
为 SW_SHOWNORAML的时候为一般大小显示方式。
为 SW_SHOWMAXIMIZED的时候为最大化显示方式。
为 SW_SHOWMINNOACTIVE的时候程序将显示在任务栏上。
*/
{

static char szAppName[] = TEXT(" HelloWin"); // 预先定义一个 c风格字符串 ,稍后用于设置窗口类名称。
WNDCLASS wndclass; // 定义窗口类对象
/*
在这里不得不说一下的是,窗口类事实上是 struct结构体 ,内部有 10个分量,他们是用来于初始化窗口 类对象而用的。
这个结构体在 winuser.h头文件中定义,从方式上来说,分为 ASCII版的 WNDCLASSA和 Unicode版的 WNDCLASSW两个。
typedef struct tagWNDCLASSA {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;
typedef struct tagWNDCLASSW {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
*/

//------------------------------- 窗口 类对象初始化过程 ------------------------------------ wndclass.style = CS_HREDRAW | CS_VREDRAW;
/*
设置窗口 类对象的样式风格, CS_HREDRAW | CS_VREDRAW这两个值是 通过位运算的与运算结合起来的。
表示了窗口在改变了水平和垂直大小的时候,窗口要强迫刷新。
这些通过 define定义的标识,可以在 WinUser.h头文件中找到。
#define CS_VREDRAW 0x0001
#define CS_HREDRAW 0x0002
#define CS_DBLCLKS 0x0008
#define CS_OWNDC 0x0020
#define CS_CLASSDC 0x0040
#define CS_PARENTDC 0x0080
#define CS_NOCLOSE 0x0200
#define CS_SAVEBITS 0x0800
#define CS_ BYTEALIGNCLIENT 0x1000
#define CS_ BYTEALIGNWINDOW 0x2000
#define CS_GLOBALCLASS 0x4000
#define CS_IME 0x00010000
*/

wndclass.lpfnWndProc = WndProc ; // 指定窗口的处理函数为 WndProc, WndProc将处理 windows消息。
wndclass.cbClsExtra = 0; // 窗口类无扩展
wndclass.cbWndExtra = 0; // 窗口实例无扩展
wndclass.hInstance = hInstance; // 指定当前应用程序实例句柄 ,也就是程序当前的标识号。
wndclass.hIcon = LoadIcon (NULL ,IDI_APPLICATION);
/*
通过 LoadIcon函数设置应用程序窗口标题的 icon图标。
HICON LoadIcon (HINSTANCE hInstance,LPCTSTR lpIconName);
函数返回 HICON类型的图标句柄。
第一个参数表示当前应用程序的窗口句柄 ,第二个参数表示图标。
默认状态下,第一个参数为 NULL,第二个为 IDI_APPLICATION,表示使用系统默认提供的图标,可以在 WinUser.h头文件中找到。
#define IDI_APPLICATION 32512
*/
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW ) ;
/*
通过 LoadCursor函数设置应用程序窗口光标样式。
HCURSOR LoadCursor (HINSTANCE hInstance,LPCTSTR lpCursorName);
函数返回 HCURSOR类型的光标句柄。
第一个参数表示当前应用程序的窗口句柄 ,第二个参数表示光标。
默认状态下,第一个参数为 NULL,第二个为 IDC_ARROW,表示使用系统默认提供的光标,可以在 WinUser.h头文件中找到。
#define IDC_ARROW MAKEINTRESOURCE(32512)
*/
wndclass.hbrBackground = (HBRUSH ) GetStockObject (WHITE_BRUSH);
/*
通过 GetStockObject函数设置应用程序窗口的背景颜色。
HGDIOBJ GetStockObject ( int fnObject);
函数返回 HCURSOR类型的 GDI对象句柄,为了程序能够正确执行,必须把 HGDIOBJ类型强制转换成 HBRUSH画刷句柄。
参数表示当前使用的画刷颜色。
这些常量的定义可以在 WinGDI.h头文件中找到。
#define WHITE_BRUSH 0
#define LTGRAY_BRUSH 1
#define GRAY_BRUSH 2
#define DKGRAY_BRUSH 3
#define BLACK_BRUSH 4
#define NULL_BRUSH 5
#define HOLLOW_BRUSH NULL_BRUSH
*/
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; // 窗口 类对象的名称
//-----------------------------------------------------------------------------------------
RegisterClass (& wndclass);
/*
注册窗口类 ,参数为窗口 类对象的指针。
函数原形为 :
ATOM RegisterClass (CONST WNDCLASS * lpWndClass);
*/

//-------------------------- 实例化过程 -------------------------------------------------
HWND hwnd ; // 创建用于保存窗口句柄的对象,窗口句柄是系统识别不同窗口的依据,它只是个代号。
hwnd = CreateWindow(
szAppName, // 窗口类名称
" 你好世界 ", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口样式
CW_USEDEFAULT, // 初始的窗口 x轴位置
CW_USEDEFAULT, // 初始的窗口 y轴位置
CW_USEDEFAULT, // 初始的窗口 x轴大小
CW_USEDEFAULT, // 初始的窗口 y轴大小
NULL, // 父窗口句柄
NULL, // 窗口功能表句柄
hInstance, // 应用程序实例句柄
NULL // 建立参数,这个参数可以存取后面程序中可能引用到的资料。
);
/*
在窗口 类对象的初始化过程中,我们定义了窗口的一些简单一般特征,比如背景颜色呀,光标呀,等等。
但是在利用 CreateWindow创建窗口的时候可以设置更多的细节,比如窗口标题这些。
函数原形如下:
HWND CreateWindow ( LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
一旦窗口创建成功,那么 CreateWindow将返回窗口句柄,也就是窗口代号,值保存在窗口句柄对象 hwnd中。
*/
ShowWindow ( hwnd, iCmdShow);
/*
在执行过 CreateWindow函数后,在系统的内部窗口已经创建成功了。
但为了要把窗口显示在桌面上,我们还必须调用 ShowWindow函数。
其函数原形如下:
BOOL ShowWindow (WND hWnd,int iCmdShow);
参数 1是需要显示的窗口句柄,第二个则是传递给 WinMain的 iCmdShow ,用来确定最开始窗口的显示方式。
在这里窗口的显示方式,主要是指最大化,最小化这些。
*/
UpdateWindow ( hwnd);
/*
UpdateWindow 这个函数的作用是用于重 绘显示区域。
因为如果 ShowWindow函数的 iCmdShow从 WinMain获得的参数是 SW—— SHOWNORMAL,那么窗口的显示区域就会 被背景画刷覆盖,
调用 UpdateWindow函数会通过发送给窗口消息处理函数 WndProc一个 WM_PAINT消息,通过这个消息完成重 绘显示区域的工作。
*/
//-----------------------------------------------------------------------------------------
//---------------------------- 消息循环 -------------------------------------------------
/*
当调用过 UpdateWindow函数后,窗口已经显示在了桌面屏幕上,接下来要做的工作是处理消息。
windows 应用程序可以接受各种消息包括键盘,鼠标,等等。
windows 是通过监视各种输入设备,把发生的事件转化为消息的,并将消息保存在消息队列中。
最后当前的应用程序从自己的消息队列中按顺序检索消息,并把每一个消息发送到所对应的窗口消息处理函数总去,这里是指 WndProc。
*/
MSG msg ; // 建立消息对象。
/*
MSG 是个结构体类型,在 WinUser.h头文件中可以找到。
typedef struct tagMSG{
HWND hwnd;// 窗口句柄
UINT message;// 消息识别字,在 WinUser.h头文件中可以找到,以 WM开头 ,这里就不全部举出来了。
WPARAM wParam;//32 位的消息参数,其含义和 值根据消息的不同而不同。
LPARAM lParam;//32 位的消息参数,其值和消息无关。
DWORD time;// 消息进入消息队列的时间。
POINT pt;// 消息进入消息队列时候的鼠标坐标。
# ifdef _MAC
DWORD lPrivate;
# endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
其中 POINT也是个结构体类型 ,在 WinDef.h头文件中可以找到

typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;
*/
while ( GetMessage (& msg, NULL, 0, 0))
{
/*
我们通过这个循环代码来维护消息循环,循环的执行条件是通过 GetMessage函数获得的。
函数原型如下:
BOOL GetMessage (LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);
参数一是一 个指向 msg对象的指针,剩余的参数为 NULL或 0表示程序接受它自己建立的所有窗口的消息。
windows 从消息队列取出的下一个消息将填充 MSG结构中的各成员分量。
*/
TranslateMessage (& msg); // 把虚拟键盘消息转换到字符消息,满足键盘输入的需要,参数为 msg消息对象的指针。
DispatchMessage (& msg);
/*
把当前的消息发送到窗口消息处理函数中去处理,在这里为 WndProc。
当 DispatchMessage调用结束后,循环再次重复,重新回到 GetMessage处,接着获取消息。
如果消息循环接收到 WM_QUIT消息则跳出消息循环。
*/
}
//----------------------------------------------------------------------------------------
return msg.wParam; // 返回消息结构中的 wParam成员信息。
/*
MSG 结构的 wParam成员的值是传递给 PostQuitMessage函数参数,通常是 0。
因为 PostQuitMessage函数是在结束消息循环必须调用的函数。
系统其实是执行了 return 0;结束了 WinMain函数退出了程序 ,很想控制台应用程序 main结束的时候的 return 0;,所以直接写 return 0;也不会导致程序错误。
*/
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) // 窗口消息处理函数
/*
函数返回类型为 LRESULT,是一个长整数,修饰 CALLBACK表示此函数为回调函数,函数的返回类型,和参数顺序都必须按照系统的规定设置。
参数一为窗口句柄,第二个参数是无符号整型数据,用于标识接受的消息,最后两个参数为 32位的消息参数,提供了更多关于消息的信息。
WPARAM 和 LPARAM都表示的是长整数,该函数的四个参数与 MSG结构的前四个成员相同。
消息处理函数,通常是 windows自己调用的,当然程序作者也可以通过调用 SendMessage函数直接呼叫自己的窗口消息处理函数,只是在这里暂时不讨论。
*/
{
HDC hdc; // 创建设备描述句柄对象
PAINTSTRUCT ps; // 创建绘制结构对象
/*
PAINTSTRUCT 结构包含了一些窗口消息处理程序,可以用来更新窗口显示区域中的信息。
结构如下:
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved [32];
} PAINTSTRUCT, *PPAINTSTRUCT;
*/
RECT rect; // 创建矩形结构对象
/*
此结构的定义如下:
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
*/
switch (message) // 通过 switch和 case结构来确定处理什么样的消息,如果不想处理某些消息则把消息传递给 DefWindowProc函数处理。
{
case WM_CREATE: // 当窗口创建的时候获得 WM_CREATE消息
PlaySound (TEXT("C://online.wav"),NULL,SND_FILENAME|SND_ASYNC); // 播放声音
return 0; // 窗口消息处理函数如果正在处理消息必须返回 0
case WM_PAINT: // 通知窗口更新显示区域的信息
/*
当窗口刚开始建立的时候,整个显示区域都是无效的,因为程序还没有在窗口上绘制任何东西。
第一条 WM_PAINT消息通常发生在调用 UpdateWindows函数的时候,告诉窗口消息处理函数在显示区域绘制一些东西。
事实上当用户把 wndclass.style设置成 CS_HREDRAW | CS_VREDRAW后,一旦用户改变窗口大小,就会把显示区域当作无效,这时候就会收到 WM_PAINT消息。
*/
/*
通常在处理 WM_PAINT消息的时候,总是以 BeginPaint开头和 EndPaint结尾的。
*/
hdc = BeginPaint ( hwnd, & ps);
/*
调用 BeginPaint函数可以传回设备句柄,这里指的是显示器的代号和显示器的驱动程序。
因为在窗口显示区域要显示文字或者图形都需要用到设备句柄。
它的函数原形为:
HDC BeginPaint (
HWND hwnd, // handle to window
LPPAINTSTRUCT lpPaint // paint information
);
它实际的功能是:当发现窗口显示区域的背景还没有被清除的时候,则由 windows来删除它。
我们前面在 wndclass结构中设置了画刷为白色,这么以来系统就用白色来遮盖桌面的颜色,这样窗口显示区域就变成白色了。
*/
GetClientRect ( hwnd,&rect); // 设置窗口显示区域的尺寸,同时它也负责获得窗口改变后的窗口显示区域的尺寸信息。
DrawText ( hdc,TEXT(" 中国软件开发实验室 ,http://www.cndev-lab.com"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER); // 绘制文字在窗口显示区域中
/*
DT_SINGLELINE|DT_CENTER|DT_VCENTER  表示的是文字显示的方式,这些在 WinUser.h头文件中定义。
*/
EndPaint ( hwnd,&ps); // 结束指定窗口的绘图
return 0;
case WM_DESTROY: // 当窗口销毁的时候会返回此信息,比如 ALT+F4或关闭窗口的时候,系统默认调用 DestroyWindow ()函数撤消窗口。
PostQuitMessage (0);
/*
处理 WM_DESTROY消息必须调用 PostQuitMessage函数,该函数 向消息队列中发送 WM_QUIT消息,让程序退出消息循环。
应用程序可以在响应这个消息的同时做一些其它结束的工作。
*/
return 0;
}
return DefWindowProc ( hwnd, message, wParam, lParam); // 处理 不于处理的消息
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: