WindowsAPI学习笔记
WindowsAPI学习笔记
Windows窗口程序基础
在屏幕上显示一个窗口的过程一般包括以下步骤,也就是入口函数WinMain的执行流程:
注册窗口类
在注册之前,要先填写
RegisterClassEx
函数的参数WNDCLASSEX
结构的各个字段。创建窗口
显示窗口、刷新窗口客户区
运行消息循环
获取消息、转换消息、将消息分发到回调函数WindowProc处理。
接下来分别介绍每一个步骤:
注册窗口类
RegisterClassEx
函数用于注册窗口类,其函数原型如下:
1 | ATOM RegisterClassEx(_In_const WNDCLASSEX* lpwcx); |
其中参数lpwcx是一个指向WNDCLASSEX
结构的指针,调用RegisterClassEx函数必须先初始化此结构:
1 | typedef struct tagWNDCLASSEX { |
每一项可使用的取值可查看《深入浅出WindowsAPI程序设计》对应此处的内容。
创建窗口
创建窗口的函数是CreateWindowEx
,其函数原型如下:
1 | HWND CreateWindowEx( |
显示窗口
ShowWindow
函数用于设置指定窗口的显示状态:
1 | BOOL ShowWindow( |
在ShowWindow
函数执行前,窗口已经在Windows内部创建了,但此时还未显示。其作用是设置指定窗口的显示状态,其通过指定nCmdShow参数来设置。
刷新窗口客户区
UpdateWindow
函数通过向窗口发送WM_PAINT消息来刷新窗口客户区,该函数将WM_PAINT消息发送给指定的窗口过程,其绕过消息队列,直接调用窗口过程。适用于修改窗口内容后立即刷新内容。
1 | BOOL UpdateWindow(_In_ HWND hWnd); // 填写要更新的窗口句柄 |
消息循环
程序运行后会发生很多事件,Windows为每个程序维护消息队列,事件发生后系统将其转化为消息放置在队列中,程序会通过以下的消息循环对其进行处理:
GetMessage
函数用于从调用线程的消息队列中获取消息:
1 | BOOL GetMessage( |
MSG结构体用于存放函数获取的消息的具体信息,其定义如下:
1 | typedef struct tagMSG{ |
pt字段是一个POINT结构,表示消息发生时的光标位置,其结构在windef.h中定义如下:
1 | typedef struct tagPOINT { |
窗口过程
窗口过程是程序的消息处理中心,无论是队列还是非队列消息窗口过程都会为程序处理。窗口过程的定义如下:
1 | LRESULT CALLBACK WindowProc( |
窗口过程的名称可以任意命名,只要不与其他函数名称冲突即可,WNDPROC是窗口过程指针类型
1 | typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM); |
WM_CREATE消息:
WinMain调用CreateWindowEx函数创建窗口后,系统会向窗口发送WM_CREATE消息。其是窗口过程较早收到的的消息之一,程序常常会在此处做一些初始化工作。
WM_CLOSE消息:
当用户关闭窗口时,系统会向窗口发送WM_CLOSE消息,DefWindowsProc函数会对其处理,即调用DestroyWindow函数销毁窗口,DestroyWindow函数会向窗口发送WM_DESTROY消息。DefWindowProc函数不会处理该消息,需要我们自己处理:在WM_DESTROY消息中调用PostQuitMessage函数,该函数向消息队列中发送WM_QUIT消息,GetMessage函数收到该消息后返回0,从而结束消息循环退出程序。
其他消息处理
DefWindowProc函数用于调用Windows提供的默认窗口过程,可确保程序的每个消息都得到处理。
1
2
3
4
5LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam);
4. WM_PAINT重绘消息
WinMain调用UpdateWindow函数时,系统会向窗口发送WM_PAINT消息。这是Windows编程中很重要的一条消息,当窗口客户区的部分或全部变为无效(首次创建、调整大小、最小化等)时,系统会向窗口发送WM_PAINT消息,要求窗口重绘客户区。
若一个窗口不对WM_PAINT消息进行处理,那么应交由DefWindowProc
函数处理,其依次调用BeginPaint和EndPaint函数,BeginPaint
函数用于获取设备上下文,EndPaint
函数用于释放设备上下文。
BeginPaint函数原型如下:
1
2
3
4HDC BeginPaint(
_In_ HWND hWnd, // 窗口句柄
_Out_ LPPAINTSTRUCT lpPaint // PAINTSTRUCT结构指针
);
PAINTSTRUCT结构用于存放BeginPaint函数获取的设备上下文,其定义如下:
1
2
3
4
5
6
7
8typedef struct tagPAINTSTRUCT {
HDC hdc; // 设备上下文句柄
BOOL fErase; // 是否擦除背景
RECT rcPaint; // 需要重绘的区域
BOOL fRestore; // 是否恢复设备上下文
BOOL fIncUpdate; // 是否进行增量更新
BYTE rgbReserved[32]; // 保留字段
} PAINTSTRUCT, *PPAINTSTRUCT;
EndPaint函数原型如下:
1
2
3
4BOOL EndPaint(
_In_ HWND hWnd, // 窗口句柄
_In_ const PAINTSTRUCT* lpPaint // PAINTSTRUCT结构指针
);
一个完整的Windows窗口程序实例:
1 |
|
杂项
播放音乐
播放音乐的函数是PlaySound
,其函数原型如下:
1 | BOOL PlaySound( |
其中fdwSound参数可以取以下值:
- SND_ASYNC:异步播放(开始播放后立即返回)
- SND_SYNC:同步播放(播放完音乐后函数才返回)
- SND_LOOP:循环播放
显示字符串
TextOut
函数用于在指定位置显示一个字符串,其函数原型如下:
1 | BOOL TextOut( |