示例代码:
/*
Windows C UI 窗口界面
*/
#include<Windows.h>
#include<strsafe.h> //字符串安全函数头文件
#define TEXTCOUNT 128
#define TEXTHIGHT 20
/*********************************
消息回调函数声明,参数等同于 消息结构体(MSG)的前4个成员
HWND :窗口句柄
UINT :消息
WPARAM :消息参数
LPARAM :消息参数
**********************************/
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
/*********************************************************************************************
程序主入口
HINSTANCE hInstance :HINSTANCE为实例句柄,句柄无非是一个数值,
程序用它来标识某些东西。在此该句柄唯一标识我们这个程序。
HINSTANCE hPrevInstance :前一个实例句柄,在win32程序中这一概念已不再采用,
因此WinMain的第二个参数通常是NULL。
PSTR szCmdLine :PSTR是一个字符指针,用来运行程序的命令行,
有些程序在启动时用它来把文件装入内存。
int iCmdShow :用来指明程序最初如何显示:正常显示、最大化到全屏、最小化到任务栏。
************************************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("MyFirstWindow"); //定义窗口类的名称
HWND hwnd;//窗口句柄
MSG msg; //消息结构体
WNDCLASS wndclass;//窗口类
wndclass.style = CS_HREDRAW | CS_VREDRAW; //指定窗口类型,可以使用按位或操作符组合起来
wndclass.lpfnWndProc = WndProc; //指定窗口过程(必须是回调函数)
wndclass.cbClsExtra = 0; //预留的额外空间,一般为 0
wndclass.cbWndExtra = 0; //预留的额外空间,一般为 0
wndclass.hInstance = hInstance; //应用程序的实例句柄
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //为所有基于该窗口类的窗口设定一个图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //为所有基于该窗口类的窗口设定一个鼠标指针
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //指定窗口背景色
wndclass.lpszMenuName = NULL; //指定窗口菜单
wndclass.lpszClassName = szAppName; //指定窗口类名
if (!RegisterClass(&wndclass))//注册当前窗口类
{
MessageBox(NULL, TEXT("程序需要在 Windows NT 框架下才能运行!"), szAppName, MB_ICONERROR);
return 0;
}
//创建窗口句柄
hwnd = CreateWindow(szAppName, //窗口类名称
TEXT("C UI 练习"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口的风格样式
CW_USEDEFAULT, //初始化 X 坐标
CW_USEDEFAULT, //初始化 Y 坐标
CW_USEDEFAULT, //初始化 X 方向尺寸
CW_USEDEFAULT, //初始化 Y 方向尺寸
NULL, //父窗口句柄
NULL, //窗口菜单句柄
hInstance, //程序实例句柄
NULL); //创建参数
//显示和更新已创建的窗口
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);//相当于刷新
//消息循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//消息翻译:函数将虚拟键消息转换成字符消息
DispatchMessage(&msg);//消息分发:把消息传给操作系统,再有操作系统调用当前窗口实例句柄的回调函数
}
return msg.wParam;
}
//消息回调函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc; //设备环境句柄 使用GDI函数绘制图形
PAINTSTRUCT ps;//绘制窗口图形参数
RECT rect;
TCHAR txt[TEXTCOUNT];
size_t txtlen;
errno_t err;//捕获错误 NULL | 0
static int cxChar, cyChar; //存储当前程序字体大小和行距
TEXTMETRIC tmt;
switch (message)
{
case WM_CREATE://当程序被创建时
hdc = GetDC(hwnd); //公用 获取设备环境句柄
GetTextMetrics(hdc,&tmt );
cxChar = tmt.tmAveCharWidth;//字体宽度
cyChar = tmt.tmExternalLeading + tmt.tmHeight;//字体高度
ReleaseDC(hwnd, hdc); //释放环境句柄(GetDC -> ReleaseDC 必须成对出现)
return 0;
case WM_PAINT://要求一个窗口重绘自己
hdc = BeginPaint(hwnd, &ps);//获取绘制设备环境句柄 函数为指定窗口进行绘画作准备,并用将和绘画有关的信息填充到一个 PAINTSTRUCT 结构中。
GetClientRect(hwnd, &rect);//获取客户区(绘制区)获取窗口客户区的坐标,客户区坐标指定客户区的左上角和右下角。
for (size_t i = 0; i < 10; i++)
{
/*wsprintf(txt, TEXT("NO.%d : 我是第 【%d】 行文字。"), i + 1, i + 1);
TextOut(hdc, 0, i*TEXTHIGHT, txt, lstrlen(txt));*/
//使用字符串处理安全函数
StringCchPrintf(txt, TEXTCOUNT, TEXT("NO.%d : 我是第 【%d】 行文字。"), i + 1, i + 1);//格式化字符串
err=StringCchLength(txt, TEXTCOUNT, &txtlen);//获取字符串长度
TextOut(hdc, cxChar, i * cyChar, txt, txtlen);
}
cxChar = GetSystemMetrics(SM_CXSCREEN); //获取分辨率宽
cyChar = GetSystemMetrics(SM_CYSCREEN);//获取分辨率的高
DrawText(hdc, TEXT("你好,世界!你好 C语言!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);//绘制文本
StringCchPrintf(txt, TEXTCOUNT, TEXT("当前环境的分辨率:%d * %d px."), cxChar,cyChar);//格式化字符串
err=StringCchLength(txt, TEXTCOUNT, &txtlen);//获取字符串长度
TextOut(hdc, 500, 200, txt, txtlen);
EndPaint(hwnd, &ps);//函数标记指定窗口的绘画过程结束 这个函数在每次调用 BeginPaint 函数之后被调用(释放设备描述表),但仅仅在绘画完成以后。(函数要匹配成对使用 BeginPaint-> EndPaint)
return 0;
case WM_CLOSE://点你关闭按钮时
if (MessageBox(hwnd, TEXT("你真的要关闭吗?"), TEXT("提示:"), MB_YESNO)==IDYES)
{
PostQuitMessage(0);
}
else
{
return 0;
}
case WM_LBUTTONUP:
MessageBox(hwnd, TEXT("你双击了鼠标左键!"), TEXT("提示:"), MB_DEFMASK);
return 0;
//case WM_DESTROY://一个窗口被销毁
// PostQuitMessage(0);
// return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);//默认消息处理方式
}
/*
窗口的创建流程:
【1】初始化窗口类结构:WNDCLASS
【2】注册窗口类:RegisterClass(&wndclass)
【3】创建窗口实例:CreateWindow
【4】显示窗口:ShowWindow
【5】更新窗口:UpdateWindow
【6】消息循环: CALLBACK WndProc
关于消息机制:
【1】消息队列是先进先出(FIFO)形式。
【2】WM_PAINT ; WM_TIMER 和 WM_QUIT 这三个消息属于特例。操作系统会把它们时刻放在消息队列的最后面。
【3】队列化消息 和 非队列化消息(由windows 直接发送给窗口)
*/
项目配配置:VS2019
WNDCLASS 结构体
Windows 的窗口总是基于窗口类来创建的,窗口类同时确定了处理窗口消息的窗口过程(回调函数)。
在创建应用程序窗口之前,必须调用 RegisterClass 函数来注册窗口类。该函数只需要一个参数,即指向 WNDCLASS 窗口类的指针。因为 WNDCLASS 类包含了窗口所拥有的基本属性。
typedef struct tagWNDCLASSW {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
成员 | 含义 |
---|---|
style | 指定窗口类型,可以使用按位或操作符组合起来 |
lpfnWndProc | 指定窗口过程(必须是回调函数) |
cbClsExtra | 预留的额外空间,一般为 0 |
cbWndExtra | 预留的额外空间,一般为 0 |
hInstance | 应用程序的实例句柄 |
hIcon | 为所有基于该窗口类的窗口设定一个图标 |
hCursor | 为所有基于该窗口类的窗口设定一个鼠标指针 |
hbrBackground | 指定窗口背景色 |
lpszMenuName | 指定窗口菜单 |
lpszClassName | 指定窗口类名 |
style 风格样式选项:
类风格 | 含义 |
---|---|
CS_VREDRAW | 移动或者调整窗口的高度(垂直方向)时,重绘整个窗口 |
CS_HREDRAW | 移动或者调整窗口的宽度(水平方向)时,重绘整个窗口 |
CS_DBLCLKS | 当用户光标在窗口内双击时,允许发送双击消息给窗口过程 |
CS_OWNDC | 给予每个窗口实例分配一个唯一的 DC(注意,尽管这样是很方便,但它必须慎重使用,因为每个 DC 大约要占 800 个字节的内存) |
CS_CLASSDC | 该窗口类的所有窗口实例都共享一个窗口类 DC |
CS_PARENTDC | 1. 将子窗口的裁剪区域设置到父窗口的 DC 中去,这样子窗口便可以在父窗口上绘制自身。(注意,这是子窗口从系统缓存中获取 DC,而不是使用父窗口的 DC。)2. 指定该风格可以提高系统性能 |
CS_NOCLOSE | 禁止系统菜单的关闭选项 |
CS_SAVEBITS | 1. 以位图形式保存被该窗口遮挡的屏幕部分,当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息2. 该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失3. 设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存 |
CS_BYTEALIGNCLIENT | 在字节边界上(在 x 方向上)定位窗口的用户区域的位置 |
CS_BYTEALIGNWINDOW | 在字节边界上(在 x 方向上)定位窗口的位置 |
CS_GLOBALCLASS | 1. 当调用 CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的 hInstance 参数和注册窗口类时传递给 RegisterClass 的 hInstance 参数不同2. 如果不指定该风格,则这两个 hInstance 必须相同 |
CreateWindow函数:
CreateWindow 函数创建一个重叠式窗口、弹出式窗口或子窗口。它指定窗口类,窗口标题,窗口风格,以及窗口的初始位置及大小(可选的)。函数也指该窗口的父窗口或所属窗口(如果存在的话),及窗口的菜单。
若要使用除 CreateWindow 函数支持的风格外的扩展风格,则使用 CreateWindowEx 函数代替 CreateWindow 函数。
API 函数原型:
注释:In 说明该参数是输入的,opt 说明该参数是可选参数。
WINUSERAPI
HWND
WINAPI
CreateWindowExA(
_In_ DWORD dwExStyle, //正在创建的窗口的扩展窗口样式
_In_opt_ LPCSTR lpClassName, // 窗口类名称
_In_opt_ LPCSTR lpWindowName, // 窗口标题
_In_ DWORD dwStyle, // 窗口风格,或称窗口格式
_In_ int X, // 初始 x 坐标
_In_ int Y, // 初始 y 坐标
_In_ int nWidth, // 初始 x 方向尺寸
_In_ int nHeight, // 初始 y 方向尺寸
_In_opt_ HWND hWndParent, // 父窗口句柄
_In_opt_ HMENU hMenu, // 窗口菜单句柄
_In_opt_ HINSTANCE hInstance, // 程序实例句柄
_In_opt_ LPVOID lpParam); // 创建参数
WINUSERAPI
HWND
WINAPI
CreateWindowExW(
_In_ DWORD dwExStyle,
_In_opt_ LPCWSTR lpClassName,
_In_opt_ LPCWSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int X,
_In_ int Y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam);
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif // !UNICODE
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_GAMES) */
#pragma endregion
#define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
#ifdef UNICODE
#define CreateWindow CreateWindowW
#else
#define CreateWindow CreateWindowA
#endif // !UNICODE
参数说明:
参数 | 含义 |
---|---|
dwExStyle | MSDN描述 |
lpClassName | 1. 窗口类名称,可以是一个指向 NULL 结束的字符串或一个整型数值2. 如果是字符串,它指定了窗口的类名。这个类名可以是任何用函数 RegisterClass 注册的类名,或是任何预定义的控制类名3. 如是一个整型量,它是由此前调用 theGlobalAddAtom 函数产生的全局量。这个小于 0xC000 的 16 位数必须是 lpClassName 参数字的低 16 位,该参数的高位必须是 0 |
lpWindowName | 1. 窗口标题,一个指向 NULL 结束的字符串指针2. 如果窗口风格指定了标题条,由 lpWindowName 指向的窗口标题将显示在标题条上3. 当使用 Createwindow 函数来创建控制例如按钮,选择框和静态控制时,可使用 lpWindowName来指定控制文本 |
dwStyle | 指定创建窗口的风格(详见下方↓) |
x | 1. 指定窗口的初始水平位置(x 坐标)2. 对一个层叠或弹出式窗口,x 参数是屏幕坐标系的窗口的左上角的初始 x 坐标3. 对于子窗口,x 是子窗口左上角相对父窗口客户区左上角的初始 x 坐标4. 如果该参数被设为 CW_USEDEFAULT 则系统为窗口选择缺省的左上角坐标并忽略 y 参数,CW_USEDEFAULT 只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则 x 和 y 参数被设为零。 |
y | 1. 指定窗口的初始垂直位置(y 坐标)2. 对一个层叠或弹出式窗口,y 参数是屏幕坐标系的窗口的左上角的初始 y 坐标3. 对于子窗口,y 是子窗口左上角相对父窗口客户区左上角的初始 y 坐标4. 对于列表框,y 是列表框客户区左上角相对父窗口客户区左上角的初始 y 坐标5. 如果层叠窗口是使用 WS_VISIBLE 风格位创建的并且 x 参数被设为 CW_USEDEFAULT,则系统将忽略 y 参数 |
nWidth | 1. 以设备单元指明窗口的宽度2. 对于层叠窗口,nWidth 的值或是屏幕坐标的窗口宽度或是 CW_USEDEFAULT3. 若 nWidth 是 CW_USEDEFAULT,则系统为窗口选择一个默认的高度和宽度(默认宽度为从初始 x 坐标开始到屏幕的右边界,缺省高度为从初始 y 坐标开始到目标区域的顶部。),CW_USEDEFAULT 只对层叠窗口有效,如果为弹出式窗口和子窗口设定 CW_USEDEFAULT 标志则 nWidth 和 nHeight 被设为零 |
nHeight | 1. 以设备单元指明窗口的高度2. 对于层叠窗口,nHeight 是屏幕坐标的窗口宽度3. 若 nWidth 被设为 CW_USEDEFAULT,则系统忽略 nHeight 参数,自动为 nWidth 和 nHeight 设置默认参数 |
hWndParent | 1. 指向被创建窗口的父窗口或所有者窗口的句柄2. 若要创建一个子窗口或一个从属窗口,需提供一个有效的窗口句柄3. 创建一个单纯的消息窗口,可以提供 HWND_MESSAGE 或提供一个己存在的消息窗口的句柄 |
hMenu | 1. 指向窗口菜单句柄,或依据窗口风格指明一个子窗口标识2. 对于层叠或弹出式窗口,hMenu 指定窗口使用的菜单:如果使用了菜单类,则 hMenu 可以为 NULL3. 对于子窗口,hMenu 指定了该子窗口标识(一个整型量),一个对话框使用这个整型值将事件通知父类。应用程序确定子窗口标识,这个值对于相同父窗口的所有子窗口必须是唯一的 |
hInstance | 与窗口相关联的模块实例的句柄 |
lpParam | 1. 指向一个值的指针,该值传递给窗口 WM_CREATE 消息。该值通过在 IParam 参数中的 CREATESTRUCT 结构传递2. 如果应用程序调用 CreateWindow 创建一个 MDI 客户窗口,则 lpParam 必须指向一个CLIENTCREATESTRUCT 结构 |
dwStyle 窗口风格解析:
窗口风格 | 含义 |
---|---|
WS_BORDER | 创建一个带边框的窗口 |
WS_CAPTION | 创建一个有标题框的窗口(包含了 WS_BODER 风格) |
WS_CHILD | 创建一个子窗口,这个风格的窗口不能拥有菜单也不能与 WS_POPUP 风格合用 |
WS_CHILDWINDOW | 与 WS_CHILD 相同 |
WS_CLIPCHILDREN | 当在父窗口内绘图时,排除子窗口区域,在创建父窗口时使用这个风格 |
WS_CLIPSIBLINGS | 1. 排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到 WM_PAINT 消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口2. 如果未指定该风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口 |
WS_DISABLED | 1. 创建一个初始状态为禁止的子窗口,一个禁止状态的窗口不能接受来自用户的输入信息2. 在窗口创建之后,可以调用 EnableWindow 函数来启用该窗口 |
WS_DLGFRAME | 创建一个带对话框边框风格的窗口,这种风格的窗口不能带标题条 |
WS_GROUP | 1. 指定一组“控制窗口”的第一个“控制窗口”2. 这个“控制窗口”组由第一个“控制窗口”和随后定义的“控制窗口”组成,自第二个“控制窗口”开始每个“控制窗口”具有 WS_GROUP 风格3. 每个组的第一个“控制窗口”带有 WS_TABSTOP 风格,从而使用户可以在组间移动4. 用户随后可以使用光标在组内的控制间改变键盘焦点 |
WS_HSCROLL | 创建一个有水平滚动条的窗口 |
WS_ICONIC | 创建一个初始状态为最小化状态的窗口,与 WS_MINIMIZE 风格相同 |
WS_MAXIMIZE | 创建一个初始状态为最大化状态的窗口 |
WS_MAXIMIZEBOX | 创建一个具有最大化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格 |
WS_MINIMIZE | 创建一个初始状态为最小化状态的窗口,与 WS_ICONIC 风格相同 |
WS_MINIMIZEBOX | 创建一个具有最小化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格 |
WS_OVERLAPPED | 产生一个层叠的窗口,一个层叠的窗口有一个标题条和一个边框,与 WS_TILED 风格相同 |
WS_OVERLAPPEDWINDOW | 相当于(WS_OVERLAPPED / WS_CAPTION / WS_SYSMENU / WS_THICKFRAME / WS_MINIMIZEBOX / WS_MAXIMIZEBOX),与 WS_TILEDWINDOW 风格相同 |
WS_POPUP | 创建一个弹出式窗口,该风格不能与 WS_CHILD 风格同时使用。 |
WS_POPUPWINDOW | 相当于(WS_POPUP / WS_BORDER / WS_SYSMENU),但 WS_CAPTION 和 WS_POPUPWINDOW 必须同时设定才能使窗口某单可见 |
WS_SIZEBOX | 创建一个可调边框的窗口,与 WS_THICKFRAME 风格相同 |
WS_SYSMENU | 创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格 |
WS_TABSTOP | 1. 创建一个“控制窗口”,在用户按下 Tab 键时可以获得键盘焦点。2. 按下 Tab 键后使键盘焦点转移到下一具有 WS_TABSTOP 风格的“控制窗口” |
WS_THICKFRAME | 创建一个具有可调边框的窗口,与 WS_SIZEBOX 风格相同 |
WS_TILED | 产生一个层叠的窗口,一个层叠的窗口有一个标题和一个边框,与 WS_OVERLAPPED 风格相同 |
WS_TILEDWINDOW | 相当于(WS_OVERLAPPED / WS_CAPTION / WS_SYSMENU / WS_THICKFRAME / WS_MINIMIZEBOX / WS_MAXIMIZEBOX),与 WS_OVERLAPPEDWINDOW 风格相同 |
WS_VISIBLE | 创建一个初始状态为可见的窗口 |
WS_VSCROLL | 创建一个有垂直滚动条的窗口 |
函数返回值:
- 如果函数成功,返回值为新窗口的句柄;
- 如果函数失败,返回值为 NULL。
在 Winodows 的定义中包含着许多大写标识符,这些标识符有很多都是以两个或三个字母作为前缀,且其后紧跟一个下划线:
CS_HREDRAW | DT_VCENTER | SND_FILENAME |
CS_VREDRAW | IDC_ARROW | WM_CREATE |
CW_USEDEFAULT | IDI_APPLICATION | WM_DESTROY |
DT_CENTER | MB_ICONERROR | WM_PAINT |
DT_SINGLELINE | SND_ASYNC | WS_OVERLAPPEDWINDOW |
这些标识符其实都是宏定义,前缀标明该常量所属的一般类别,含义如下表:
前缀 含义
CS 类风格选项(ClassStyle)
CW 创建窗口选项(CreateWindow)
DT 文本绘制选项(DrawText)
IDI 图标的 ID 号(IDIcon)
IDC 光标的 ID 号(IDCursor)
MB 消息框选项(MessageBox)
SND 声音选项(Sound)
WM 窗口消息(WindowsMessage)
WS 窗口风格(WindowStyles)
ShowWindow 函数:用于设置窗口的显示状态。
应用程序第一次调用 ShowWindow 时,应该使用 WinMain 函数的 nCmdshow 参数作为它的 nCmdShow 参数。在随后调用 ShowWindow 函数时,必须使用下列显示方式中的一个给定值,而不是由 WinMain 函数的 nCmdSHow 参数指定的值。
API 原型:
BOOL
WINAPI
ShowWindow(
_In_ HWND hWnd,
_In_ int nCmdShow);
参数解析:
参数 | 含义 |
---|---|
hWnd | 窗口句柄 |
nCmdShow | 控制窗口如何显示,如果发送应用程序的程序提供了 STARTUPINFO 结构,则应用程序第一次调用 ShowWindow 时该参数被忽略。否则,在第一次调用 ShowWindow 函数时,该值应为在函数 WinMain 中 nCmdShow 参数。 |
nCmdShow 参数可以为下列值之一:
显示方式 | 含义 |
---|---|
SW_FORCEMINIMIZE | 1. 最小化窗口,即使拥有窗口的线程被挂起也会最小化 2. 在从其他线程最小化窗口时才使用这个参数 |
SW_HIDE | 隐藏窗口并激活其他窗口 |
SW_MAXIMIZE | 最大化指定的窗口 |
SW_MINIMIZE | 最小化指定的窗口并且激活在 Z 序中的下一个顶层窗口 |
SW_RESTORE | 1. 激活并显示窗口2. 如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置3. 在恢复最小化窗口时,应用程序应该指定这个标志。 |
SW_SHOW | 在窗口原来的位置以原来的尺寸激活并显示窗口 |
SW_SHOWDEFAULT | 依据在 STARTUPINFO 结构中指定的 SW_FLAG 标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给 CreateProcess 函数的。 |
SW_SHOWMAXIMIZED | 激活窗口并将其最大化 |
SW_SHOWMINIMIZED | 激活窗口并将其最小化 |
SW_SHOWMINNOACTIVE | 1. 窗口最小化2. 在窗口激活的情况下,这个值跟SW_SHOWMINIMIZED 很相似 |
SW_SHOWNA | 1. 以窗口原来的位置以原来的尺寸显示窗口2. 在窗口激活的情况下,这个值跟 SW_SHOW 很相似 |
SW_SHOWNOACTIVATE | 1. 以窗口最近一次的位置和尺寸显示窗口2. 在窗口激活的情况下,这个值跟 SW_SHOWNORMAL 很相似 |
SW_SHOWNORMAL | 1. 激活并显示一个窗口2. 如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小3. 应用程序在第一次显示窗口的时候应该指定此标志 |
GetMessage 函数:的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
该函数只能获取调用线程的消息,不能获得其他线程的消息。成功获取消息后,线程将从消息队列中删除该消息。
使用 GetMessage 函数,如果消息队列为空,函数会一直等待直到有消息到来才有返回值。如果希望函数立刻返回(无论是否获取消息),请使用 PeekMessage 函数。
API 函数原型:
/*
* Message Function Templates
*/
WINUSERAPI
BOOL
WINAPI
GetMessageA(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax);
WINUSERAPI
BOOL
WINAPI
GetMessageW(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax);
#ifdef UNICODE
#define GetMessage GetMessageW
#else
#define GetMessage GetMessageA
#endif // !UNICODE
#if defined(_M_CEE)
#undef GetMessage
__inline
BOOL
GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
)
{
#ifdef UNICODE
return GetMessageW(
#else
return GetMessageA(
#endif
lpMsg,
hWnd,
wMsgFilterMin,
wMsgFilterMax
);
}
#endif /* _M_CEE */
参数解析:
参数 | 含义 |
---|---|
lpMsg | 指向 MSG 结构的指针,用于存放获取到的消息 |
hWnd | 1. 需要获取消息的窗口的句柄,该窗口必须属于当前线程2. 当其值是 NULL 时,将获取所有的当前线程的窗口消息和线程消息3. 当其值是 -1 时,只获取当前线程消息 |
wMsgFilterMin | 指定被可以被获取的消息值的最小整数(消息其实就是一个被定义的整数) |
wMsgFilterMax | 指定被可以被获取的消息值的最小整数 |
返回值:
-
如果函数取得 WM_QUIT 之外的其他消息,返回值是非 0;
-
如果函数取得 WM_QUIT 消息,返回值是 0;
-
如果出现了错误,返回值是 -1。
备注:
-
应用程序通常根据 GetMessage 函数的返回值决定是否结束消息循环并退出程序;
-
如果 hWnd 参数不为零,则 GetMessage 函数只获取属于 hWnd 窗口的消息,以及被 IsChild 函数确定为 hWnd 的子窗口的消息;
-
wMsgFilterMin 和 wMsgFilterMax 参数限定消息获取的范围,如果二者都为 0,则消息获取的范围为所有消息;
-
注意,即便你通过 wMsgFilterMin 和 wMsgFilterMax 参数限定消息获取的范围,但 WM_QUIT 不受此范围影响(无法阻止此消息被 PeekMessage 函数获取);
-
调用此函数的过程中,如果接收到非排队消息 —— 也就是由该线程调用 SendMessage, SendMessageCallback, SendMessageTimeout, 或 SendNotifyMessage 发送给所属窗口的消息 —— 系统先暂时挂起等待,然后再获取过滤器匹配的第一个队列消息。如果不指定过滤器,那么按照以下顺序获取消息:
Sent messages
Posted messages
Input (hardware) messages and system internal events
Sent messages (again)
WM_PAINT messages
WM_TIMER messages
- PeekMessage 函数通常不会从消息队列中删除 WM_PAINT 消息,WM_PAINT 会持续保留在消息队列中直到它们被处理,除非一个 WM_PAINT 消息指定的区域为 NULL。
WM_QUIT, WM_PAINT, WM_TIMER 会被特殊处理,它们总是放在队列的最后面,直到没有其它消息的时候才被处理,连续的 WM_PAINT 消息将被合并成一个以提高绘图效率。
- 如果一个顶层窗口停止响应的消息超过几秒钟,系统认为窗口没有响应,并使用一个备用窗口替代,该窗口具有相同的 Z 序列、位置、尺寸和视觉属性。这使得用户可以移动、调整大小,甚至关闭该应用程序。然而,这些仅仅是动作,现有的程序事实上仍然没有响应(为了提高用户体验而制作的假象)。当一个程序被调试时,系统并不会为其生成备用窗口。