一个基于Visual Studio 2017的Windows窗口程序
无装饰,超朴素,除了流程一无所有
1 新建项目
在Visual Studio 2017中新建一个Windows窗口程序
新建一个解决方案
解决方案处右键–》添加–》项目,打开新建项目向导
选择
Visual C++
/Windows桌面
下的Windows桌面向导在弹出窗口中选择
桌面应用程序
,并勾选空项目
在源文件夹下新建C++源文件simpleWinApp.cpp
2 编写Windows窗口程序
头文件
#include <Windows.h>
程序结构
函数组成
1. 入口函数
1 | int _stdcall _tWinMain ( HINSTANCE hInstance, |
- hInstance:实例句柄。当可执行文件加载到内存中时,操作系统使用该值来标识该可执行文件
- hPrevInstance:没有任何意义。它曾在16位Windows中使用,但现在始终为零。
- pCmdLine:作为Unicode字符串包含命令行参数。
- nCmdShow:是一个标志,指示是否将主应用程序窗口最小化,最大化或正常显示。
- 返回值:操作系统不使用该返回值,但是可以使用该返回值将状态代码传送给您编写的其他程序。
2. 窗口过程
1 | // 处理窗口消息 |
宏定义和函数调用方式扫盲
__stdcall
是 Standard Call 的缩写,是 C++ 的标准调用方式:所有参数从右到左依次入栈,如果是调用类成员的话,最后一个入栈的是 this 指针。#define CALLBACK __stdcall
LRESULT
1
2typedef LONG_PTR LRESULT;
typedef _W64 long LONG_PTR, *PLONG_PTR; // _W64在VS2013后就取消了WPARAM
1
2typedef UINT_PTR WPARAM;
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;LPARAM
1
typedef LONG_PTR LPARAM;
入口函数
_tWinMain
源码
1 | int _stdcall _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, |
相关类定义
WNDCLASS
窗口类
1 | typedef struct tagWNDCLASSW { |
常见style
CS_VREDRAW
:移动或者调整窗口的高度(垂直方向)时,重绘整个窗口CS_HREDRAW
:移动或者调整窗口的宽度(水平方向)时,重绘整个窗口
宏定义扫盲
typedef unsigned int UINT;
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
LPCWSTR
1
2typedef _Null_terminated_ CONST WCHAR *LPCWSTR, *PCWSTR;
typedef wchar_t WCHAR; // wc, 16-bit UNICODE character
相关函数定义
CreateWindow
1 | HWND WINAPI CreateWindow( |
返回值
- 如果函数成功,返回值为新窗口的句柄;
- 如果函数失败,返回值为 NULL。
修饰符扫盲
_In_
说明该参数是输入的_opt_
说明该参数是可选参数
常见dwStyle风格
WS_BORDER
:创建一个带边框的窗口WS_CAPTION
:创建一个有标题框的窗口(包含了 WS_BODER 风格)WS_HSCROLL
:创建一个有水平滚动条的窗口WS_VSCROL
:创建一个有垂直滚动条的窗口WS_SYSMENU
:创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格WS_OVERLAPPED
:产生一个层叠的窗口,一个层叠的窗口有一个标题条和一个边框WS_THICKFRAME
:创建一个具有可调边框的窗口,与 WS_SIZEBOX 风格相同WS_MAXIMIZEBOX
:创建一个具有最大化按钮的窗口WS_MINIMIZEBOX
:创建一个具有最小化按钮的窗口WS_OVERLAPPEDWINDOW
:相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_TILEDWINDOW 风格相同
MessageBox
1 | int WINAPI MessageBox( |
返回值
- 消息框中返回一个整数值
- 该值指示用户单击了哪个按钮
返回值 | 含义 |
---|---|
IDOK | 用户按下了“确认”按钮 |
IDCANCEL | 用户按下了“取消”按钮 |
IDABORT | 用户按下了“中止”按钮 |
IDRETRY | 用户按下了“重试”按钮 |
IDIGNORE | 用户按下了“忽略”按钮 |
IDYE | 用户按下了“是”按钮 |
IDNO | 用户按下了“否”按钮 |
uType参数取值
按钮 | 含义 |
---|---|
MB_OK | 默认值,有一个“确认”按钮在里面 |
MB_YESNO | 有“是”和“否”两个按钮在里面 |
MB_ABORTRETRYIGNORE | 有“中止”,“重试”和“跳过”三个按钮在里面 |
MB_YESNOCANCEL | 有“是”,“否”和“取消”三个按钮在里面 |
MB_RETRYCANCEL | 有“重试”和“取消”两个按钮在里面 |
MB_OKCANCEL | 有“确定”和“取消”两个按钮在里面 |
图标 | 含义 |
---|---|
MB_ICONWARNING | 惊叹号 |
MB_ICONINFORMATION | 字母i |
MB_ICONQUESTION | 问号 |
MB_ICONERROR | 叉号 |
ShowWindow
1 | BOOL WINAPI ShowWindow( |
返回值
- 如果窗口之前可见,则返回值为非 0
- 如果窗口之前被隐藏,则返回值为 0
使用方式
ShowWindow 函数用于设置窗口的显示状态。
应用程序第一次调用 ShowWindow 时,应该使用 WinMain 函数的 nCmdshow 参数作为它的 nCmdShow 参数。在随后调用 ShowWindow 函数时,必须使用下列显示方式中的一个给定值,而不是由 WinMain 函数的 nCmdSHow 参数指定的值。
nCmdShow常用参数
SW_SHOW
:在窗口原来的位置以原来的尺寸激活并显示窗口SW_HIDE
:隐藏窗口并激活其他窗口
UpdateWindow
1 | BOOL UpdateWindow( |
返回值
- 如果函数调用成功,返回值为非 0
- 如果函数调用不成功,返回值为 0
功能说明
- 如果窗口更新的区域不为空,UpdateWindow 函数通过发送一个 WM_PAINT 消息来更新指定窗口的客户区
- 如果更新区域为空,则不发送消息
GetMessage
1 | BOOL WINAPI GetMessage( |
返回值
- 如果函数取得 WM_QUIT 之外的其他消息,返回值是 true
- 如果函数取得 WM_QUIT 消息,返回值是 false
功能说明
- GetMessage 函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中
- 该函数只能获取调用线程的消息,不能获得其他线程的消息。成功获取消息后,线程将从消息队列中删除该消息
- 如果消息队列为空,函数会一直等待直到有消息到来才有返回值
参数说明
hWnd
- 值不为NULL,指向的窗口必须属于当前线程
- 其值是 NULL 时,将获取所有的当前线程的窗口消息和线程消息
- 当其值是 -1 时,只获取当前线程消息
wMsgFilterMin
和wMsgFilterMax
参数限定消息获取的范围,如果二者都为 0,则消息获取的范围为所有消息
PeekMessage
1 | BOOL WINAPI PeekMessage( |
返回值
- 如果获取到有效的消息,返回值是 true;
- 如果获取不到消息,返回值是 false
与GetMessage的区别
- 使用 GetMessage 函数,如果消息队列为空,函数会一直等待直到有消息到来才有返回值
- 而 PeekMessage 函数会立即返回结果
wRemoveMsg取值
PM_NOREMOVE
:消息被获取后不从消息队列中删除PM_REMOVE
:消息被获取后并从消息队列中删除PM_NOYIELD
:防止系统释放任何正在等待被调用的线程PM_QS_INPUT
:处理鼠标和键盘消息PM_QS_PAINT
:处理绘图消息PM_QS_POSTMESSAGE
:处理所有 posted 的消息,包括计时器和快捷键消息PM_QS_SENDMESSAGE
:处理所有 send 的消息
TranslateMessage
1 | BOOL WINAPI TranslateMessage( |
函数功能
- 将虚拟键消息转换为字符消息
- 字符消息被寄送到当前线程的消息队列里
- 当下一次线程调用函数 GetMessage 或 PeekMessage 时被读出
返回值
- 如果消息被转换(字符消息被寄送到当前线程的消息队列里)则返回非零值;
- 如果消息是 WM_KEYDOWN,WM_KEYUP WM_SYSKEYDOWN 或 WM_SYSKEYUP,返回非零值,不考虑转换;
- 如果消息没被转换(字符消息没被寄送到调用线程的消息队列里)则返回值是零。
DispatchMessage
1 | LRESULT WINAPI DispatchMessage( |
函数功能
分派一个消息给窗口过程(回调函数)
返回值
返回值是窗口过程返回的值
窗口过程
源码
1 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
相关函数
PostQuitMessage
1 | VOID WINAPI PostQuitMessage( |
函数功能
- 向系统表明有个线程提出终止(退出)请求
- 实际上是发送一个 WM_QUIT 消息给线程的消息队列并立即返回
DefWindowProc
1 | LRESULT WINAPI DefWindowProc( |
返回值
消息处理结果
函数功能
- 调用默认的窗口过程来处理我们不感兴趣的任何消息
- 该函数是为了确保每个消息都被处理
Windows常用消息和含义
3 完整代码
1 | #include <Windows.h> |