Windows消息机制
1.1 基本概念
API: Application Programming Interface, 应用程序编程接口。编写Windows应用程序本质上就是调用Windows提供的大量API函数,这些API函数大多数都在头文件Windows.h中声明。
SDK: Software Development Kit, 软件开发包。指的是由厂商提供的软件开发包,内含API函数库,帮助文档,示例程序,开发工具等等。
以上两个概念都是很宽泛的,没有特指某个特定的设备,语言或者是厂商。只要是在已经准备好的接口之上进行软软件开发,我们都可以把这个编程接口成为API, 把实现该借口的库,使用文档,开发工具统称为SDK。
窗口:Windows平台下应用程序和用户进行交互的图形接口,他表现为屏幕上的矩形区域。一个典型的窗口包含客户区和非客户区两大块,客户区域通常用来显示文字和图形,是窗口的主题;非客户区域则包含菜单栏,标题栏,系统菜单,最大最小化框等等。除了典型的窗口外,应用程序弹出的对话框和消息框也属于窗口,Window桌面其实也是由系统创建的窗口。
句柄: 资源的标识称为句柄,常见的资源包括窗口,图标,光标等等,他们在创建的时候都会被分配内存,而句柄就是这段内存的标识,可以理解成是指针的一种抽象。需要记住的几个句柄类型:HWND(窗口句柄),HICON(图标句柄),HBRUSH(画刷句柄),HCURSOR(光标句柄)。
1.2 Windows API中常见宏定义
宏名 | 实际类型 | |
---|---|---|
CHAR: | char | |
WCHAR: | wchar_t | |
LPARAM: | long | |
WPARAM: | unsigned int | |
LRESULT | long | |
LPSTR: | char * | |
LPWSTR: | wchar_t * | |
LPCSTR: | const char * | |
LPCWSTR: | cong wchar_t * | |
WORD: | unsigned short | |
DWORD: | unsigned long | |
TCHAR: | 如果定义UNICODE则为WCHAR,否则是CHAR | |
LPTSTR: | 如果定义UNICODE则为LPWSTR,否则是LPSTR | |
LPCTSTR: | 如果定义UNICODE则为LPCWSTR,否则是LPCSTR | |
__TEXT(): | 根据UNICODE决定是否转换为宽字符 | |
TEXT(): | __TEXT() |
一些跟字符有关的函数也通过宏的方法封装了宽字符和ASCII两种版本:
宏名 | 实际类型 |
---|---|
wsprintf | sprintfA或者sprintfW |
MessageBox | MessageBoxA或者MessageBoxW |
_tmain | main或者wmain |
_tWinMain | WinMain或者wWinMain |
其中**_tXXX系列宏在tchar.h**中定义,很多函数都由这种版本
1.3 消息和消息队列
不同于控制台应用程序,Windows桌面应用程序采用事件驱动机制,换句话说程序的执行不再是简单的顺序执行(配合循环和分支结构),事件驱动机制下程序可以响应事件(event)来完成特定功能,而事件驱动的底层原理就是Windows的消息机制。用户的操作(鼠标点击,键盘按下等等)都会被操作系统感知并封装为消息(message)再投放到应用程序的消息队列中,而应用程序内部通过消息循环不断从消息队列中取出并**解析(translate)消息,之后应用程序会将消息再次分派(dispatch)**给操作系统并由操作系统调用窗口过程函数来对特定消息做出响应。
消息:Windows通过MSG结构体来封装消息
typedef struct tagMSG{
HWND hwnd;//消息所属窗口的句柄
UINT message;//消息常量(WM_XXX),实际上是一个整数标识
WPARAM wParam;//附加信息
LPARAM lParam;//附加信息
DWORD time;//消息产生的事件
POINT pt;//消息产生时光标位置
}MSG;
消息队列:一个由操作系统给程序维护的数据结构,该程序所创建的窗口的全部队列消息都会被操作系统塞进程序消息队列中
**队列消息和非队列消息:**队列消息是要进入消息队列的,非队列消息则直接通过窗口过程响应。
1.4 WinMain函数
windows console application的入口函数是main(),windows application的入口函数是WinMain(),二者类似都是被可执行文件中的启动代码调用。
int WINAPI WinMain(//WINAPI是 对__stdcall的宏定义,Win32 API均要求显示声明该调用约定,而标准C函数则为__cdecl(vc默认)
HINSTANCE hInstance,//该程序当前实例的句柄
HINSTANCE hPrevInstance,//该程序上一个实例的句柄,对于Win32 app而言该参数总为NULL,无意义
LPSTR lpCmdLine,//命令行参数,调用程序时传入的参数会被系统存入这个参数中
int nCmdShow//程序显示状态(窗口最大化、最小化、隐藏之类的),和应用程序无关,由调用方指定
) ;
创建窗口:大概分为四个步骤
- 创建窗口类
- 注册窗口类
- 创建窗口
- 显示更新窗口
创建窗口类:创建一个WNDCLASS结构体的实例
typedef struct _WNDCLASS{
uint style;//窗口类样式,CS_XXX宏
WNDCLASS lpfnWndProc;//窗口过程,typedef LRESULT (CALLBACK* WNDCLASS)(HWND, UINT, WPARAM, LPARAM);,因此WNDCLASS用来定义函数指针类型,lpfnWndProc是函数指针变量
int cbClsExtra;//类附加信息,通常设置0