Windwos编程学习个人笔记-2 窗口和消息
书中示例代码如下:
1
#include
<
windows.h
>
2
3 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
4
5 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
6 PSTR szCmdLine, int iCmdShow)
7 {
8 static TCHAR szAppName[] = TEXT ( " HelloWin " ) ;
9 HWND hwnd ;
10 MSG msg ;
11 WNDCLASS wndclass ;
12
13 wndclass.style = CS_HREDRAW | CS_VREDRAW ;
14 wndclass.lpfnWndProc = WndProc ;
15 wndclass.cbClsExtra = 0 ;
16 wndclass.cbWndExtra = 0 ;
17 wndclass.hInstance = hInstance ;
18 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
19 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
20 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
21 wndclass.lpszMenuName = NULL ;
22 wndclass.lpszClassName = szAppName ;
23
24 if ( ! RegisterClass ( & wndclass))
25 {
26 MessageBox (NULL, TEXT ( " This program requires Windows NT! " ),
27 szAppName, MB_ICONERROR) ;
28 return 0 ;
29 }
30
31 hwnd = CreateWindow (szAppName, // window class name
32 TEXT ( " The Hello Program " ), // window caption
33 WS_OVERLAPPEDWINDOW, // window style
34 CW_USEDEFAULT, // initial x position
35 CW_USEDEFAULT, // initial y position
36 CW_USEDEFAULT, // initial x size
37 CW_USEDEFAULT, // initial y size
38 NULL, // parent window handle
39 NULL, // window menu handle
40 hInstance, // program instance handle
41 NULL) ; // creation parameters
42
43 ShowWindow (hwnd, iCmdShow) ;
44 UpdateWindow (hwnd) ;
45
46 while (GetMessage ( & msg, NULL, 0 , 0 ))
47 {
48 TranslateMessage ( & msg) ;
49 DispatchMessage ( & msg) ;
50 }
51 return msg.wParam ;
52 }
53
54 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
55 {
56 HDC hdc ;
57 PAINTSTRUCT ps ;
58 RECT rect ;
59
60 switch (message)
61 {
62 case WM_CREATE:
63 PlaySound (TEXT ( " hellowin.wav " ), NULL, SND_FILENAME | SND_ASYNC) ;
64 return 0 ;
65
66 case WM_PAINT:
67 hdc = BeginPaint (hwnd, & ps) ;
68
69 GetClientRect (hwnd, & rect) ;
70
71 DrawText (hdc, TEXT ( " Hello, Windows 98! " ), - 1 , & rect,
72 DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
73
74 EndPaint (hwnd, & ps) ;
75 return 0 ;
76
77 case WM_DESTROY:
78 PostQuitMessage ( 0 ) ;
79 return 0 ;
80 }
81 return DefWindowProc (hwnd, message, wParam, lParam) ;
82 }
2
3 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
4
5 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
6 PSTR szCmdLine, int iCmdShow)
7 {
8 static TCHAR szAppName[] = TEXT ( " HelloWin " ) ;
9 HWND hwnd ;
10 MSG msg ;
11 WNDCLASS wndclass ;
12
13 wndclass.style = CS_HREDRAW | CS_VREDRAW ;
14 wndclass.lpfnWndProc = WndProc ;
15 wndclass.cbClsExtra = 0 ;
16 wndclass.cbWndExtra = 0 ;
17 wndclass.hInstance = hInstance ;
18 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
19 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
20 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
21 wndclass.lpszMenuName = NULL ;
22 wndclass.lpszClassName = szAppName ;
23
24 if ( ! RegisterClass ( & wndclass))
25 {
26 MessageBox (NULL, TEXT ( " This program requires Windows NT! " ),
27 szAppName, MB_ICONERROR) ;
28 return 0 ;
29 }
30
31 hwnd = CreateWindow (szAppName, // window class name
32 TEXT ( " The Hello Program " ), // window caption
33 WS_OVERLAPPEDWINDOW, // window style
34 CW_USEDEFAULT, // initial x position
35 CW_USEDEFAULT, // initial y position
36 CW_USEDEFAULT, // initial x size
37 CW_USEDEFAULT, // initial y size
38 NULL, // parent window handle
39 NULL, // window menu handle
40 hInstance, // program instance handle
41 NULL) ; // creation parameters
42
43 ShowWindow (hwnd, iCmdShow) ;
44 UpdateWindow (hwnd) ;
45
46 while (GetMessage ( & msg, NULL, 0 , 0 ))
47 {
48 TranslateMessage ( & msg) ;
49 DispatchMessage ( & msg) ;
50 }
51 return msg.wParam ;
52 }
53
54 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
55 {
56 HDC hdc ;
57 PAINTSTRUCT ps ;
58 RECT rect ;
59
60 switch (message)
61 {
62 case WM_CREATE:
63 PlaySound (TEXT ( " hellowin.wav " ), NULL, SND_FILENAME | SND_ASYNC) ;
64 return 0 ;
65
66 case WM_PAINT:
67 hdc = BeginPaint (hwnd, & ps) ;
68
69 GetClientRect (hwnd, & rect) ;
70
71 DrawText (hdc, TEXT ( " Hello, Windows 98! " ), - 1 , & rect,
72 DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
73
74 EndPaint (hwnd, & ps) ;
75 return 0 ;
76
77 case WM_DESTROY:
78 PostQuitMessage ( 0 ) ;
79 return 0 ;
80 }
81 return DefWindowProc (hwnd, message, wParam, lParam) ;
82 }
在WNDCLASS结构中最重要的两个字段是第二个和最后一个,第二个字段(lpfnWndProc) 是依据这个类别来建立的所有窗口所使用的窗口消息处理程序的地址。
1.wndclass.style = CS_HREDRAW | CS_VREDRAW ;
窗口类别样式,,每当窗口的水平方向大小(CS_HREDRAW)或者垂直方向大小(CS_VREDRAW)改变之后,窗口要完全重画。CS_HREDRAW ,CS_VREDRAW等在WINUSER.H中定义。
2.wndclass.lpfnWndProc = WndProc ;
将这个窗口类别的窗口消息处理程序设定为WndProc。
3.wndclass.cbClsExtra = 0 ;
4.wndclass.cbWndExtra = 0 ;
3,4 参数用于在窗口类别结构和Windows内部保存的窗口结构中预留一些额外空间,程序可以根据需要来使用预留的空间,将值设定为0。
否则,将被当成「预留的字节数」。
5.wndclass.hInstance = hInstance
程序的执行实体句柄。
6.wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION)
加载图标。。图标是一个小的位图图像,它对使用者代表程序,将出现在Windows工作列中和窗口的标题列的左端。
LoadIcon的第一个参数为NULL,表示取得预先定义图示的句柄。在加载自定义的图标时,图标应该存放在磁盘上.exe程序文件中,第一个参数就应
该被设定为程序的执行实体句柄hInstance。
第二个参数代表图示。图示ID在WINUSER。H中定义。例如: IDI_APPLICATION。
7.wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
加载光标。
使用方法与LoadIcon类似。
8.wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
设定窗口背景颜色
GetStockObject 检索预定义的备用笔、刷子、字体或者调色板的句柄。
9 wndclass.lpszMenuName = NULL ;
指定窗口类别菜单。
为NULL,表示没有应用程序菜单。
10 wndclass.lpszClassName = szAppName
给出窗口类别的文字名称
注册窗口 RegisterClass(&wndclass)
需要配置内存,以保存窗口类别的信息。
建立窗口CreateWindow ( szAppName,
TEXT ("The Hello Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL)
「window class name」的参数是szAppName,它含有字符串「HelloWin」-这是程序注册的窗口类别名称。这就是我们建立的窗口联结窗口类别的方式。
「window caption」 标题显示的内容。
「window style」 窗口的风格。WS_OVERLAPPEDWINDOW 可以在WinUser.h 中查看到它的定义。描述了窗口包含的元素等信息。还有其他几种。例如WS_POPUPWINDOW,WS_CHILDWINDOW等。
「initial x position」 「initial y position」「initial x size」「initial y size」 用于描述窗口相对于屏幕左上角的位置,以及窗口的大小。参数都是CW_USEDEFAULT,表明希望Windows使用内定尺寸
「parent window handle」 父窗口句柄。通常,如果窗口之间存在有父子关系,则子窗口总是出现在父窗口的上面。
「window menu handle」 窗口菜单句柄。
「program instance handle」 程序执行实体句柄
「creation parameters」 建立参数,用这个参数存取稍后程序中可能引用到的数据。
显示窗口 ShowWindow(hwnd, iCmdShow)
在CreateWindow呼叫传回之后,Windows内部已经建立了这个窗口。这就是说,Windows已经配置了一块内存,用来保存在CreateWindow呼叫中指定窗口的全部信息跟一些其它信息,而Windows稍后就是依据窗口句柄找到这些信息的。然而,光是这样子,窗口并不会出现在视讯显示器上,需要调用函数ShowWindow。
第一个参数是刚刚用CreateWindow建立的窗口句柄。
第二个参数是作为参数传给WinMain的iCmdShow。它确定最初如何在屏幕上显示窗口,是一般大小、最小化还是最大化。
指示窗口自我更新 UpdateWindow(hwnd)
它经由发送给窗口消息处理程序(即HELLOWIN.C中的WndProc函数)一个WM_PAINT消息做到这一点。
Windows为当前执行的每个Windows程序维护一个「消息队列」。在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中。
while ( GetMessage (&msg, NULL, 0, 0)) //只要从消息队列中取出消息的message字段不为WM_QUIT(其值为0x0012),GetMessage就传回一个非零值。
//WM_QUIT消息将导致GetMessage传回0。
{
TranslateMessage (&msg) ;//将msg结构传给Windows,进行一些键盘转换
DispatchMessage (&msg) ;//Windows该消息发送给适当的窗口消息处理程序,让它进行处理
}
typedef struct tagMSG
{
HWND hwnd ; //接受消息的窗口句柄
UINT message ; //消息。是一些数值。在WinUser.h中定义。如 WM_LBUTTONDOWN,其值为0x0201。。
WPARAM wParam ; //一个32位的「message parameter(消息参数)」,其含义和数值根据消息的不同而不同。
LPARAM lParam ; //一个32位的消息参数,其值与消息有关
DWORD time ; //消息放入消息队列中的时间。
POINT pt ; //消息放入消息队列时的鼠标坐标。
}MSG, * PMSG ;
typedef struct tagPOINT
{
LONG x ;
LONG y ;
}
窗口消息处理程序总是定义为如下形式:
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
第一个参数hwnd是接收消息的窗口的句柄
第二个参数与MSG结构中的message字段相同
最后两个参数都是32位的消息参数,提供关于消息的更多信息。这些参数包含每个消息型态的详细信息。有时消息参数是两个存放在一起的16位值,而有时消息参数又是一个指向字符串或数据结构的指针。
PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) 播放声音文件
第一个参数是声音文件的名称。第二个参数只有当声音文件是一种资源时才被使用。第三个参数指定一些选项,指定第一个参数是一个文件名,并且异步地播放声音。
WM_PAINT的处理几乎总是从一个BeginPaint呼叫开始:而以一个EndPaint呼叫结束:
hdc = BeginPaint (hwnd, &ps) ; // 第一个参数都是程序的窗口句柄,第二个参数是指向型态为PAINTSTRUCT的结构指针。
// PAINTSTRUCT结构中包含一些窗口消息处理程序,可以用来更新显示区域的内容
EndPaint (hwnd, &ps) ; // EndPaint释放设备内容句柄,使之不再有效。
GetClientRect (hwnd, &rect) ;
第一个参数是程序窗口的句柄。第二个参数是一个指标,指向一个RECT型态的rectangle结构。该结构有四个LONG字段,分别为left、top、right和bottom。
DrawText ( hdc, TEXT ("Hello, Windows 98!"), -1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
DrawText可以输出文字(正如其名字所表明的一样)。由于该函数要输出文字,第一个参数是从BeginPaint传回的设备内容句柄,第二个参数是要输出的文字,第三个参数是 -1,指示字符串是以字节0终结的。DrawText最后一个参数是一系列位旗标,它们均在WINUSER.H中定义(虽然由于其显示输出的效果,使得DrawText像一个GDI函数呼叫,但它确实因为相当高级的画图功能而成为User模块的一部分。旗标指示了文字必须显示在一行上,水平方向和垂直方向都位于第四个参数指定的矩形中央。
PostQuitMessage (0) ;
该函数在程序的消息队列中插入一个WM_QUIT消息。