/*下列注释函数均在平台SDK文档中说明,并在不同的头文件中声明,其中绝大多数在WINUSER.H中声明。*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; // 窗口过程;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow) //程序入口点;
{
static TCHAR szAppName[] = TEXT (“HelloWin”) ;
HWND hwnd ; //窗口句柄类HWND;
MSG msg ; //P54 消息;
WNDCLASS wndclass ; //P47 注册窗口类,生成对象;解释:窗口类定义了窗口的一般特征,因此可以使用同一窗口类创建许多不同的窗口。
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
//1.。。见上:CS_HREDRAW 窗口的水平方向尺寸;CS_VREDRAW 窗口的垂直方向尺寸;这两个标示符确保了文本串既是在改变了窗口大小后仍位于窗口中央。
wndclass.lpfnWndProc = WndProc ;
//2.。。见上:即此程序的第二个函数。其处理基于这个窗口类创建的所有窗口的全部信息。在c语言中像这样在语句中使用函数名时,实际引用提供的是指向函数的指针。
//lpfn “指向函数的长指针”
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
//3和4.。。上面两个域用于在类结构和windows内部保存的窗口结构中预留一些额外空间;程序可以根据需要来使用预留的空间,此处没有使用,所以赋值为0; cb “count of bytes(字节数)”
wndclass.hInstance = hInstance ;
//5.。。上面的一个域是程序的实例句柄(他也是WinMain的参数之一)
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
//6.。。见上:LoadIcon加载图标供程序使用.
//第一个参数设为NULL是来获取预先定义(默认)的图标句柄;
//若加载定制的图标(图标应该保存在磁盘.EXE程序文件中),这个参数应该设置为程序的实例句柄hInstance;
//第二个参数标识图标,对预先定义的图标此参数是以IDI开始的标示符,标示符在WINUSER.H中定义;
//LoadIcon函数返回该图标的句柄
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
//7.。。见上:LoadCursor加载鼠标指针供程序使用;(可以参考LoadIcon)
//LoadCursor函数加载一个预先定义的鼠标光标(命名为IDC_ARROW),并返回光标的句柄。该句柄被赋给WNDCLASS结构的hCursor域。
//当鼠标光标在基于这个类创建的窗口的客户区域上出现时,它变成一个小箭头。
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
//8.。。GetStockObject获取一个图形对象,在这个例子中,是获取绘制窗口背景的刷子;
//调用则返回一个刷子(此时为‘白色刷子的’)的句柄。
wndclass.lpszMenuName = NULL ;
//9.。。上个域指定窗口类菜单。因此程序没有应用程序菜单,所以该字段被设置为NULL。
wndclass.lpszClassName = szAppName ;
//10.。。上句是给出一个类名。对于小程序类名可以和程序名相同,即存放在szAppName变量中的字符串“HelloWin”;
//上述字符串是由ASCII字符组成还是由Unicode字符组成取决于是否定义了UNICODE标示符;
if (!RegisterClass (&wndclass)) //RegisterClass 是为程序窗口注册窗口类;该函数只有一个参数,即指向WNDCLASS结构的指针。
{
MessageBox (NULL, TEXT (“This program requires Windows NT!”),
szAppName, MB_ICONERROR) ; //MessageBox 是显示消息框;
return 0 ;
}
//如下:CreateWindow 是根据窗口类创建一个窗口;返回被创建的窗口的句柄,该句柄存放在变量hwnd中。
hwnd = CreateWindow (szAppName, // window class name 是程序注册的窗口类名称;这就是如何把我们正在创建的窗口与一个窗口相联结类的方式。
TEXT (“The Hello Program”), // window caption(标题,说明)
WS_OVERLAPPEDWINDOW, // window style 窗口风格(转到定义看看):标题栏,菜单框,缩小放大关闭图标及四周表示窗口大小的边框。
//“| WS_VSCROLL | WS_HSCROLL” 加上这个 就能使用 垂直滚动(WS_VSCROLL) 和 水平滚动(WS_HSCROLL)
// WS ‘窗户风格’; 垂直 ‘vertical’; 水平 ‘horizontal’;
CW_USEDEFAULT, // initial x position 下面四个CW_USEDEFAULT都表示是使用windows默认尺寸;
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle 当创建一个“最高级”窗口,如应用程序窗口时,则“父窗口句柄”的参数设置为NULL。
NULL, // window menu handle 因窗口没有菜单则“窗口菜单句柄”设置为NULL;
hInstance, // program instance handle “程序实例句柄”设置为实例句柄,它是作为WinMain的参数传递给这个程序的;
NULL) ; // creation parameters “创建参数” 指针设置为NULL,可以用这个指针访问以后想要引用的程序中的数据;
//ShowWindow 在屏幕上显示窗口;两个参数:一、窗口句柄;二、是作为参数传给WinMain的iCmdShow,它确定最初如何在屏幕上显示窗口。
//第二个参数:1.如果窗口按常规显示,那么从WinMain接收并传递给ShowWindow的就是SW_SHOWNORMAL;
//2.最大化,则为SW_SHOWMAXIMIZED;3.若只显示在任务栏上,则为SW_SHOWMINNOACTIVE。
ShowWindow (hwnd, iCmdShow) ;
//如果第二个参数是SW_SHOWNORMAL,则窗口的客户区域被窗口类中定义的背景刷子所覆盖。函数调用UpdateWindow,导致客户区域被绘制。
UpdateWindow (hwnd) ; //指示窗口刷新自身;它通过给下面的窗口过程(即 WndProc函数)发送一个WM_PAINT消息来做到这一点。
//调用完UpdateWindow后窗口就出现在显示器上。程序现在必须读入用户键盘和鼠标输入的数据。windows为当前运行的每个windows程序维护一个“消息队列”
//在发生输入事件后,windows将事件转化为一个“消息”,并将消息放入程序消息队列中。
//程序通过执行一段称为“消息循环”的代码从消息队列中取出消息。如下:
while (GetMessage (&msg, NULL, 0, 0)) //GetMessage 从消息队列中获取消息; msg 是前面定义的‘消息’类型,其结构体具体可参见MSG的定义;
{ //NULL,0,0 是表示程序接收它自己创建的所有窗口的所有消息。详情见 P55.
TranslateMessage (&msg) ; //TranslateMessage 将msg结构传给Windows, 转换某些键盘信息;(第六章将深入讨论)
DispatchMessage (&msg) ; //DispatchMessage 将消息发送给窗口过程;
}
return msg.wParam ;
}
// 上面的都是准备工作,实际的动作发生在窗口过程中。窗口过程确定了在窗口的客户区域中显示些什么,以及窗口如何响应用户输入。
//窗口过程可以任意命名(此程序是WndProc),一个windows程序可以包含多个窗口过程,一个窗口过程总是与调用RegisterClass注册的特定窗口类相关联。
//程序一般不直接调用窗口过程。窗口过程由windows本身直接调用。通过调用SendMessage函数,程序能够直接调用它自己的窗口过程。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//四个参数与Message的前四个域是相同的,参见MSG的定义和P56。
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE: //充当的是 WndProc函数的第二个参数
PlaySound (TEXT (“hellowin.wav”), NULL, SND_FILENAME | SND_ASYNC) ;
//如上:PlaySound 播放一个声音文件;第二个参数只有当声音文件是一种资源时才被使用。
return 0 ; //窗口过程在处理消息时,必须返回0.
case WM_PAINT:
// InvalidateRect(hwnd,NULL,TRUE);
//如果在处理WM_PAINT消息时在更的矩形外绘图,可以在调BeginPaint前调用它;它使整个客户区变为无效,并擦出背景;
//但是,如果改成FALSE,则不擦出背景,原有的东西将保留在原处;详见P71整页;
hdc = BeginPaint (hwnd, &ps) ;
//对WM_PAINT的处理总是从BeginPaint(开始窗口绘制函数)的调用开始 ;第二个参数是指向类型为PAINTSTRUCT的结构指针
GetClientRect (hwnd, &rect) ;
//GetClientRect 获取窗口客户区的尺寸;第二个参数是指针,指向RECT类型的rectangle结构。
//rectangle结构有4个LONG域,分别为left,top,right,buttom(底部)。
//GetClientRect将这4个域设置为窗口客户区域的尺寸。left和top域通常设置为0,right和buttom域设置为客户区域的宽度和高度(像素点数);
DrawText (hdc, TEXT (“Hello, Windows 7!”), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
//DrawText 显示文本串(即输出为文本);
//五个参数:1、是从BeginPaint返回的设备描述表句柄;2、是要输出的文本;3、是-1,指示文本串是以字节0终结的;
/5、是一系列的位标识,均在WINUSER.H中定义;标志指示文本须显示在一行上,水平方向和垂直方向都位于第4个参数指定的矩形区域,因此输出文本显示在客户区域中央;
EndPaint (hwnd, &ps) ; //EndPaint 结束窗口绘制;第二个参数是指向类型为PAINTSTRUCT的结构指针(同上:BeginPaint函数)。
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ; //PostQuitMessage 在消息队列中插入一条“退出”消息;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ; //DefWindowProc 执行默认的消息处理(即窗口过程不予处理的消息被传给它);
}