1. Windows程序的入口函数WinMain:
int WINAPI WinMain( // App的入口函数,是一个API,由操作系统调用,以下这四个参数都是由操作系统分配并传递进来,当然后两个可以由用户指定
HINSTANCE hInstance, // 当前App的实例号
HINSTANCE hPrevInstance, // Win32里总是为NULL
// 当前App的上一个兄弟App的实例号
//(一个程序同时开多个,则各个App按照时间顺序排列,比如打开多个记事本进行编辑)
LPSTR lpCmdLine, // char *的传统C串,LP=long pointer,长指针指32位,该App的命令行参数(不包括该程序的名称)
// 如果想获得完整的命令行参数(包括命令名)则要使用GetCommandLine函数
int nCmdShow // 宏,通过命令行传参的方式决定改程序的窗口如何被(打开)显示
//(最大化、最小化、上次打开时的大小等,前缀是SW_,即show_window)
);
2. 创建窗口的四个步骤:
一、设计窗口类:
窗口类类型结构体:
typedef struct _WNDCLASS { // 窗口的类型类,相当于一个类模板,根据该模板创建相应的窗口
UINT style; // 宏,表示窗口的风格,比如水平重刷、垂直重刷等
//(表示如果窗口在水平或垂直方向伸缩时窗口要重画)
// 以CS_作为前缀,表示class style
WNDPROC lpfnWndProc; // lpfn=long pointer to function,一函数指针
// 表示该种类型窗口收到消息后由该指针指定的函数处理消息
// 即窗口的消息响应函数也称为回调函数,也成为过程函数,其调用约定为CALLBACK
// !之后会介绍回调的含义
// 类结构以及窗口结构中预留的一些额外字节空间
int cbClsExtra; // cb=count of byte,Cls=class,一般为0
// 表示给该类型类WNDCLASS结构体指定额外的字节空间以指定额外成员变量
int cbWndExtra; // 以该类型类为模板创建窗口的窗口实例的额外字节空间,一般为0
HINSTANCE hInstance; // 表示创建该窗口的App的实例号,App和窗口可以看成父子线程的关系
HICON hIcon; // 窗口的图标句柄,即窗口左上角的那个图形标识
HCURSOR hCursor; // 窗口的光标句柄,即决定光标进入窗口区域后该如何显示,如正常显示还是显示成一个十字等
HBRUSH hbrBackground; // 窗口的画刷句柄,表示窗口重画时使用何种画刷,如黑色画刷或深灰画刷等
// 画刷只能用于填充用户区域的背景颜色
// !之后会介绍用户区域以及背景颜色的概念
LPCTSTR lpszMenuName; // LPCSTR=const char *常量C串,即窗口顶部第二行菜单栏的名称
LPCTSTR lpszClassName; // sz=const string即长两字符串,该种类型窗口的类名
// 注册窗口以及创建窗口都以类名作为依据
} WNDCLASS, *PWNDCLASS;
一般地,诸如上述涉及到字符串的结构体或者API都会有两个版本,这是一个通用版本,也会有WNDCLASSA和WNDCLASSW两个版本
回调函数:一般用户在程序中都是调用操作系统的函数为其提供服务,但是对于窗口过程函数(消息响应函数)是由操作系统调用的用户定义的函数,即和一般常规的函数调用关系相反(即操作系统调用用户),一般Win32程序开始执行时操作系统会为其分配一个消息队列,该应用程序所接受的所有消息一部分会被放入消息队列中,应用程序会从消息队列中取出消息,然后跳出应用程序代码,由操作系统将消息分发给响应的过程函数(操作系统调用用户定义的过程函数),待过程函数执行完毕后,控制权再交由操作系统,重新回到应用程序代码中,对于其它消息(不会被投递到消息队列中),则会直接被操作系统送到过程函数处进行处理
过程函数可以位于应用程序中也可以位于动态链接库中
窗口的用户区:即client area,是指标题栏和窗口边框之间的区域,用户可以在这个区域自由绘图并向用户传达可视输出区域,其它区域,比如菜单栏等系统定制的区域则不能由用户任意修改,而背景色就是指用户区的背景色,用户可以在背景色基础之上绘出各种各样的图案,特别适当窗口大小改变或被遮盖后重新显示时都需要对窗口进行重绘,而重绘的步骤就是先对重绘区域刷上背景色,然后再在上面复原之前的图案以及信息
窗口类定义了窗口的基本蓝图(模型),即大体的特征,而创建窗口(CreateWindow)时,就是依据该模板创建具体的窗口资源(窗口总是基于窗口类来创建的),在这个阶段才会具体定义窗口的一些细节特征,窗口类定义中最重要的两个特征一个就是指定窗口过程函数还有一个就是窗口类的名字,因为窗口类需要过程函数来处理消息,一个类可定义多个不同细节的窗口,但同一个窗口类定义的窗口共享一个过程函数,而类的名字则是创建具体窗口的唯一依据
创建窗口类类型结构体并定义其中的字段(即类属性):
{ // WinMain函数体
WNDCLASS wndclass; // 窗口类结构
HWND hWnd; // 窗口实例句柄
MSG msg; // 消息结构
wndclass.style = CS_HREDRAW | CS_VREDRAW; // 水平重刷和垂直重刷的组合风格
wndclass.lpfnWndProc = WndProc; // 指定一个消息响应函数
wndclass.cbClsExtra = 0; // 额外空间都指定为0
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance; // 窗口实例的父线程实例号就是创建它的App的实例号,即由WinMain传入
wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ); // 加载该种类型窗口的图标
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); // 加载该种类型窗口的光标
wndclass.hbrBackground = (HBRUSH)GetStockObject( GRAY_BRUSH ); // 加载画刷
wndclass.lpszMenuName = NULL; // 这里现不设置菜单名
wndclass.lpszClassName = TEXT("HelloWin"); // 模板类的名称,即类名