一、准备工作
开发环境配置
-
编译器:Visual Studio 2022/2026(社区版免费)
-
开发语言:C/C++
-
项目类型:Windows桌面应用程序/空项目
注意:若选择空项目,请检查右下角的编码方式是否为UTF-8 with BOM,同时右键点击Project1->属性->链接器->系统->子系统中选择为窗口

二、WNDCLASS
WNDCLASS是 Windows API 中用于定义和注册窗口类的关键数据结构。它是传统 Windows GUI 编程的基础,在创建任何窗口前都必须先注册其窗口类。
2.1、基本定义
typedef struct tagWNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASS;
2.2、各成员详细说明
1. style – 窗口类样式
定义窗口的公共行为特征,常用值包括:
CS_HREDRAW // 宽度改变时重绘整个窗口
CS_VREDRAW // 高度改变时重绘整个窗口
CS_DBLCLKS // 允许接收双击消息
CS_OWNDC // 为每个窗口实例分配独立的设备上下文
CS_CLASSDC // 所有窗口实例共享一个设备上下文
CS_SAVEBITS // 保存被窗口遮盖的屏幕区域
CS_PARENTDC // 使用父窗口的设备上下文
CS_GLOBALCLASS // 注册全局类(可在不同模块使用)
CS_NOCLOSE // 禁用系统菜单的"关闭"选项
2. lpfnWndProc – 窗口过程指针
指向处理窗口消息的回调函数:
LRESULT CALLBACK WindowProc(
HWND hwnd, // 窗口句柄
UINT uMsg, // 消息ID
WPARAM wParam, // 消息参数
LPARAM lParam // 消息参数
);
3. cbClsExtra 和 cbWndExtra
-
cbClsExtra: 为窗口类结构额外分配的字节数(通常为0)
-
cbWndExtra: 为每个窗口实例额外分配的字节数,可用于存储自定义数据
4. hInstance – 应用程序实例句柄
标识注册该窗口类的模块,通常传入程序的 HINSTANCE
5. hIcon – 窗口图标
LoadIcon(NULL, IDI_APPLICATION); // 默认应用程序图标
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON)); // 自定义图标
6. hCursor – 窗口光标
LoadCursor(NULL, IDC_ARROW); // 标准箭头光标
LoadCursor(NULL, IDC_CROSS); // 十字光标
LoadCursor(NULL, IDC_HAND); // 手形光标
7. hbrBackground – 背景画刷
(HBRUSH)(COLOR_WINDOW + 1); // 使用系统窗口颜色
CreateSolidBrush(RGB(255,0,0)); // 创建红色画刷
(HBRUSH)GetStockObject(WHITE_BRUSH); // 使用白色画刷
8. lpszMenuName – 菜单资源名称
-
NULL: 无菜单
-
字符串: 菜单资源名称(如"MyMenu")
-
整数: 通过 MAKEINTRESOURCE(IDR_MENU)指定
9. lpszClassName – 窗口类名
用于标识窗口类的唯一字符串名称,后续创建窗口时需使用此名称
2.3、完整使用示例
#include <windows.h>
// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
// 1. 定义并填充WNDCLASS结构
WNDCLASS wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"MyWindowClass"; // Unicode版本
// 2. 注册窗口类
if (!RegisterClass(&wc)) {
MessageBox(NULL, L"窗口类注册失败!", L"错误", MB_ICONERROR);
return 0;
}
// 3. 使用注册的类名创建窗口
HWND hwnd = CreateWindow(
L"MyWindowClass", // 这里使用注册的类名
L"我的应用程序",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL
);
// … 显示窗口、消息循环等 …
return 0;
}
三、CreateWindowEx 函数
3.1、函数概述
HWND CreateWindowEx(
DWORD dwExStyle, // 扩展窗口样式
LPCTSTR lpClassName, // 窗口类名
LPCTSTR lpWindowName, // 窗口标题
DWORD dwStyle, // 窗口样式
int x, // 水平位置
int y, // 垂直位置
int nWidth, // 宽度
int nHeight, // 高度
HWND hWndParent, // 父窗口句柄
HMENU hMenu, // 菜单句柄或控件ID
HINSTANCE hInstance, // 实例句柄
LPVOID lpParam // 创建参数
);
作用:创建重叠窗口、弹出窗口或子窗口,是 Windows GUI 编程中最核心的函数之一。
3.2、参数详解
1. dwExStyle – 扩展窗口样式
/*
* 扩展样式在基本样式基础上提供更多控制
* 常用值:
*/
#define WS_EX_DLGMODALFRAME 0x00000001L // 窗口有双边框,不可改变大小
#define WS_EX_NOPARENTNOTIFY 0x00000004L // 子窗口创建时不发送WM_PARENTNOTIFY
#define WS_EX_TOPMOST 0x00000008L // 窗口置顶,总在最前
#define WS_EX_ACCEPTFILES 0x00000010L // 窗口接受拖放文件
#define WS_EX_TRANSPARENT 0x00000020L // 窗口透明,底层窗口可穿透显示
#define WS_EX_MDICHILD 0x00000040L // 创建MDI子窗口
#define WS_EX_TOOLWINDOW 0x00000080L // 工具窗口(不在任务栏显示)
#define WS_EX_WINDOWEDGE 0x00000100L // 带3D边框的窗口
#define WS_EX_CLIENTEDGE 0x00000200L // 客户区有凹陷边缘
#define WS_EX_CONTEXTHELP 0x00000400L // 标题栏有问号按钮
#define WS_EX_RIGHT 0x00001000L // 窗口右对齐(对阿拉伯/希伯来语有用)
#define WS_EX_RTLREADING 0x00002000L // 从右到左显示文本
#define WS_EX_LEFTSCROLLBAR 0x00004000L // 垂直滚动条在左侧
#define WS_EX_CONTROLPARENT 0x00010000L // 允许用Tab键在子窗口间导航
#define WS_EX_STATICEDGE 0x00020000L // 三维边框样式
#define WS_EX_APPWINDOW 0x00040000L // 任务栏显示窗口
#define WS_EX_LAYERED 0x00080000L // 分层窗口(支持半透明)
#define WS_EX_NOINHERITLAYOUT 0x00100000L // 不继承布局
#define WS_EX_LAYOUTRTL 0x00400000L // 从右到左布局
#define WS_EX_COMPOSITED 0x02000000L // 用双缓冲绘制所有后代窗口
#define WS_EX_NOACTIVATE 0x08000000L // 创建时不激活窗口
使用示例:
// 创建透明、置顶、有阴影的窗口
DWORD exStyle = WS_EX_LAYERED | // 支持透明度
WS_EX_TOPMOST | // 置顶窗口
WS_EX_TOOLWINDOW | // 工具窗口
WS_EX_CLIENTEDGE; // 凹陷边框
2. lpClassName – 窗口类名
/*
* 指定窗口类,可以是:
* 1. 自定义注册的窗口类名
* 2. 系统预定义类名
* 3. 控件类名
*
* 常用系统类:
*/
LPCSTR classNames[] = {
"Button", // 按钮控件
"Edit", // 编辑框控件
"Static", // 静态文本控件
"ListBox", // 列表框控件
"ComboBox", // 组合框控件
"ScrollBar", // 滚动条控件
"MDIClient", // MDI客户端窗口
"ToolbarWindow32", // 工具栏
"STATIC", // 静态文本(大写也是有效的)
"#32770" // 对话框类
};
3. lpWindowName – 窗口标题
/*
* 窗口的标题栏文本
* 对于不同类型的窗口:
* – 顶层窗口:显示在标题栏
* – 子窗口/控件:可能作为控件文本显示
* – 某些控件类型会忽略此参数
*
* 注意:可以是ANSI或Unicode字符串,需与项目字符集一致
*/
4. dwStyle – 窗口样式
/*
* 窗口样式控制窗口的外观和基本行为
* 主要分为:窗口样式、控件样式、组合样式
*/
/* ========== 基本窗口样式 ========== */
#define WS_OVERLAPPED 0x00000000L // 可重叠窗口(默认)
#define WS_POPUP 0x80000000L // 弹出窗口(无父窗口)
#define WS_CHILD 0x40000000L // 子窗口
#define WS_MINIMIZE 0x20000000L // 初始最小化
#define WS_VISIBLE 0x10000000L // 初始可见
#define WS_DISABLED 0x08000000L // 初始禁用
#define WS_CLIPSIBLINGS 0x04000000L // 裁剪兄弟窗口
#define WS_CLIPCHILDREN 0x02000000L // 裁剪子窗口
#define WS_MAXIMIZE 0x01000000L // 初始最大化
#define WS_CAPTION 0x00C00000L // 标题栏 = WS_BORDER | WS_DLGFRAME
#define WS_BORDER 0x00800000L // 细边框
#define WS_DLGFRAME 0x00400000L // 对话框边框
#define WS_VSCROLL 0x00200000L // 垂直滚动条
#define WS_HSCROLL 0x00100000L // 水平滚动条
#define WS_SYSMENU 0x00080000L // 系统菜单
#define WS_THICKFRAME 0x00040000L // 可调节边框
#define WS_GROUP 0x00020000L // 控件组开始
#define WS_TABSTOP 0x00010000L // 可用Tab键切换
#define WS_MINIMIZEBOX 0x00020000L // 最小化按钮
#define WS_MAXIMIZEBOX 0x00010000L // 最大化按钮
/* ========== 组合样式(预定义样式组合) ========== */
#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | \\
WS_CAPTION | \\
WS_SYSMENU | \\
WS_THICKFRAME | \\
WS_MINIMIZEBOX | \\
WS_MAXIMIZEBOX)
#define WS_POPUPWINDOW (WS_POPUP | \\
WS_BORDER | \\
WS_SYSMENU)
#define WS_CHILDWINDOW (WS_CHILD)
/* ========== 按钮样式 ========== */
#define BS_PUSHBUTTON 0x00000000L // 标准按钮
#define BS_DEFPUSHBUTTON 0x00000001L // 默认按钮
#define BS_CHECKBOX 0x00000002L // 复选框
#define BS_AUTOCHECKBOX 0x00000003L // 自动复选框
#define BS_RADIOBUTTON 0x00000004L // 单选按钮
#define BS_3STATE 0x00000005L // 三态按钮
#define BS_AUTO3STATE 0x00000006L // 自动三态按钮
#define BS_GROUPBOX 0x00000007L // 分组框
#define BS_USERBUTTON 0x00000008L // 用户自定义按钮
#define BS_AUTORADIOBUTTON 0x00000009L // 自动单选按钮
#define BS_PUSHBOX 0x0000000AL // 推送框
#define BS_OWNERDRAW 0x0000000BL // 自绘按钮
#define BS_TYPEMASK 0x0000000FL // 按钮类型掩码
#define BS_LEFTTEXT 0x00000020L // 文本在左侧
#define BS_TEXT 0x00000000L // 显示文本
#define BS_ICON 0x00000040L // 显示图标
#define BS_BITMAP 0x00000080L // 显示位图
#define BS_LEFT 0x00000100L // 文本左对齐
#define BS_RIGHT 0x00000200L // 文本右对齐
#define BS_CENTER 0x00000300L // 文本居中
#define BS_TOP 0x00000400L // 文本顶部对齐
#define BS_BOTTOM 0x00000800L // 文本底部对齐
#define BS_VCENTER 0x00000C00L // 文本垂直居中
#define BS_PUSHLIKE 0x00001000L // 类似按钮
#define BS_MULTILINE 0x00002000L // 多行文本
#define BS_NOTIFY 0x00004000L // 发送通知消息
#define BS_FLAT 0x00008000L // 扁平样式
#define BS_RIGHTBUTTON BS_LEFTTEXT // 同BS_LEFTTEXT
/* ========== 编辑框样式 ========== */
#define ES_LEFT 0x0000L // 左对齐
#define ES_CENTER 0x0001L // 居中
#define ES_RIGHT 0x0002L // 右对齐
#define ES_MULTILINE 0x0004L // 多行
#define ES_UPPERCASE 0x0008L // 自动转大写
#define ES_LOWERCASE 0x0010L // 自动转小写
#define ES_PASSWORD 0x0020L // 密码框(显示*)
#define ES_AUTOVSCROLL 0x0040L // 自动垂直滚动
#define ES_AUTOHSCROLL 0x0080L // 自动水平滚动
#define ES_NOHIDESEL 0x0100L // 失去焦点时不隐藏选择
#define ES_OEMCONVERT 0x0400L // 转换ANSI到OEM
#define ES_READONLY 0x0800L // 只读
#define ES_WANTRETURN 0x1000L // 多行时按Enter插入回车
#define ES_NUMBER 0x2000L // 只允许数字
/* ========== 列表框样式 ========== */
#define LBS_NOTIFY 0x0001L // 发送通知消息
#define LBS_SORT 0x0002L // 自动排序
#define LBS_NOREDRAW 0x0004L // 禁止重绘
#define LBS_MULTIPLESEL 0x0008L // 允许多选
#define LBS_OWNERDRAWFIXED 0x0010L // 自绘,固定高度
#define LBS_OWNERDRAWVARIABLE 0x0020L // 自绘,可变高度
#define LBS_HASSTRINGS 0x0040L // 包含字符串
#define LBS_USETABSTOPS 0x0080L // 识别制表符
#define LBS_NOINTEGRALHEIGHT 0x0100L // 不自动调整高度
#define LBS_NOSEL 0x4000L // 禁止选择
#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)
5. x, y, nWidth, nHeight – 位置和大小
/*
* 位置和尺寸参数:
*
* 特殊值:
* CW_USEDEFAULT – 让Windows决定位置/大小
*
* 对于顶层窗口:
* x, y: 相对于屏幕左上角
* 可以设置负值(如-100表示屏幕外)
*
* 对于子窗口:
* x, y: 相对于父窗口客户区左上角
*
* 注意:nWidth和nHeight是窗口的整个大小,包括边框和标题栏
* 要计算客户区大小,需要考虑边框、菜单栏等
*/
6. hWndParent – 父窗口句柄
/*
* 指定父窗口:
* – NULL: 无父窗口(顶级窗口)
* – HWND: 父窗口句柄
* – HWND_MESSAGE: 消息专用窗口(Windows 2000+)
*
* 关系说明:
* 1. 父子关系:子窗口限制在父窗口客户区内
* 2. 拥有者关系:通过SetWindowLong设置,被拥有窗口总在最前
* 3. 兄弟窗口:共享同一父窗口的子窗口
*/
7. hMenu – 菜单或控件ID
/*
* 此参数有双重用途:
*
* 1. 对于顶级窗口:指定菜单句柄
* HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINMENU));
*
* 2. 对于子窗口:指定控件ID
* #define ID_BUTTON 1001
* (HMENU)ID_BUTTON
*
* 3. NULL: 无菜单或使用窗口类默认菜单
*
* 注意:菜单句柄和控件ID都是HMENU类型,需强制转换
*/
8. hInstance – 应用程序实例句柄
/*
* 创建窗口的模块实例句柄
* 通常从WinMain的第一个参数获取
* 对于系统预定义控件,可以设置为NULL
*
* 重要:此句柄必须与注册窗口类时使用的hInstance一致
*/
10. lpParam – 创建参数
/*
* 传递给窗口的额外创建数据
* 在WM_CREATE和WM_NCCREATE消息中访问:
*
* 访问方式:
*/
case WM_CREATE: {
CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
LPVOID lpCreateParams = pCreate->lpCreateParams;
// 使用自定义数据
MY_DATA* pData = (MY_DATA*)lpCreateParams;
// …
}
break;
3.3、使用示例
示例1:创建标准顶层窗口
// 标准应用程序主窗口
HWND CreateMainWindow(HINSTANCE hInstance, int nCmdShow) {
// 1. 注册窗口类(假设已注册,类名为"MyWindowClass")
// 2. 创建窗口
HWND hWnd = CreateWindowEx(
0, // 无扩展样式
TEXT("MyWindowClass"), // 窗口类名
TEXT("我的应用程序"), // 窗口标题
WS_OVERLAPPEDWINDOW, // 标准窗口样式
CW_USEDEFAULT, CW_USEDEFAULT, // 位置(由Windows决定)
800, 600, // 宽度和高度
NULL, // 无父窗口
NULL, // 使用类菜单
hInstance, // 程序实例
NULL // 无额外参数
);
if (hWnd) {
ShowWindow(hWnd, nCmdShow); // 显示窗口
UpdateWindow(hWnd); // 更新窗口
}
return hWnd;
}
示例2:创建带控件的对话框风格窗口
// 创建类似对话框的窗口
HWND CreateDialogWindow(HINSTANCE hInstance) {
HWND hWnd = CreateWindowEx(
WS_EX_DLGMODALFRAME | // 对话框边框样式
WS_EX_WINDOWEDGE, // 3D边框
TEXT("MyDialogClass"), // 已注册的对话框类
TEXT("设置选项"), // 标题
WS_OVERLAPPED | WS_CAPTION | // 有标题栏
WS_SYSMENU | WS_MINIMIZEBOX, // 有系统菜单和最小化按钮
100, 100, // 位置
400, 300, // 大小
NULL, // 无父窗口
NULL, // 无菜单
hInstance,
NULL
);
return hWnd;
}
示例3:创建子窗口控件
// 创建带控件的窗口
BOOL CreateControls(HWND hWndParent, HINSTANCE hInstance) {
// 创建按钮
HWND hButton = CreateWindowEx(
0, // 无扩展样式
TEXT("BUTTON"), // 按钮类
TEXT("确定(&OK)"), // 按钮文本(&表示快捷键)
WS_CHILD | WS_VISIBLE | // 子窗口,可见
BS_PUSHBUTTON | WS_TABSTOP, // 按钮样式,可Tab切换
20, 20, // 位置
80, 30, // 大小
hWndParent, // 父窗口
(HMENU)IDC_OK_BUTTON, // 控件ID
hInstance, // 实例句柄
NULL // 无额外参数
);
if (!hButton) return FALSE;
// 创建编辑框
HWND hEdit = CreateWindowEx(
WS_EX_CLIENTEDGE, // 凹陷边框
TEXT("EDIT"), // 编辑框类
TEXT(""), // 初始文本
WS_CHILD | WS_VISIBLE | // 子窗口,可见
WS_BORDER | WS_TABSTOP | // 边框,可Tab切换
ES_LEFT | ES_AUTOHSCROLL, // 左对齐,自动水平滚动
20, 60, // 位置
200, 25, // 大小
hWndParent, // 父窗口
(HMENU)IDC_EDITBOX, // 控件ID
hInstance,
NULL
);
if (!hEdit) return FALSE;
// 创建列表框
HWND hListBox = CreateWindowEx(
WS_EX_CLIENTEDGE, // 凹陷边框
TEXT("LISTBOX"), // 列表框类
TEXT(""), // 无文本
WS_CHILD | WS_VISIBLE | // 子窗口,可见
WS_BORDER | WS_VSCROLL | // 边框,垂直滚动条
LBS_STANDARD | LBS_NOINTEGRALHEIGHT, // 标准样式
20, 100, // 位置
200, 150, // 大小
hWndParent, // 父窗口
(HMENU)IDC_LISTBOX, // 控件ID
hInstance,
NULL
);
if (!hListBox) return FALSE;
return TRUE;
}
3.4、三种字符串表示方式的区别
1. 直接使用字符串字面量 "MyWindowClass"
// 这是ANSI字符串,类型是 const char*
// 占用内存:每个字符1字节
// 局限性:无法直接表示非ASCII字符(如中文、日文等)
char* str = "MyWindowClass"; // ANSI字符串
// 如果源代码保存为ANSI编码:
"我的应用程序" // 可能显示乱码,取决于系统代码页
// 如果源代码保存为UTF-8:
"我的应用程序" // Windows API可能无法正确处理UTF-8编码
2. 使用宽字符串 L"MyWindowClass"
// 这是Unicode字符串,类型是 const wchar_t*
// 占用内存:每个字符2字节(Windows上,Linux是4字节)
// 可表示所有Unicode字符
wchar_t* wstr = L"MyWindowClass"; // 宽字符串
wchar_t* chinese = L"我的应用程序"; // 正确表示中文字符
// 注意事项:
// 1. 在Windows上,wchar_t是16位(UTF-16)
// 2. 在Linux上,wchar_t通常是32位(UTF-32)
// 3. 需要与宽字符版本的API配合使用:CreateWindowExW
3. 使用 TEXT 宏(或 _T 宏)
// TEXT是一个条件编译宏,根据项目设置自动选择编码
// 定义位置:<tchar.h> 或 <windows.h> 中
// 宏定义示例:
#ifdef UNICODE
#define TEXT(str) L##str
#else
#define TEXT(str) str
#endif
// 使用方式:
TEXT("MyWindowClass") // 自适应编码
// 根据UNICODE定义,编译时展开为:
// UNICODE定义时:L"MyWindowClass" (宽字符串)
// 未定义UNICODE时:"MyWindowClass" (ANSI字符串)
四、最简单的Windows程序代码
/* 学习笔记:最简单的Windows程序
* 文件名:SimpleWindow.c
* 功能:创建一个基本的Windows窗口
* 编译:在Visual Studio中创建Win32项目
*/
/* Windows程序必须包含的头文件 */
#include <windows.h> // 包含Windows API的核心功能
/* 全局变量声明 */
HINSTANCE hInst; // 应用程序实例句柄(Windows用来标识程序实例的唯一值)
/* 函数声明 – 程序的主要函数 */
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 参数说明:
// hwnd: 窗口句柄(窗口的唯一标识符)
// uMsg: 消息类型(如鼠标点击、键盘输入等)
// wParam和lParam: 消息的附加信息
/* 程序入口点 – WinMain函数 */
int WINAPI WinMain(
HINSTANCE hInstance, // 当前程序实例句柄
HINSTANCE hPrevInstance, // 前一个实例句柄(在32/64位Windows中总是NULL)
PSTR lpCmdLine, // 命令行参数
int nCmdShow) // 窗口显示方式
{
/* 第一步:注册窗口类 */
const wchar_t CLASS_NAME[] = L"简单窗口类"; // 窗口类名
WNDCLASS wc = {0}; // 创建窗口类结构体并初始化为0
wc.lpfnWndProc = WindowProc; // 指定窗口消息处理函数
wc.hInstance = hInstance; // 设置程序实例
wc.lpszClassName = CLASS_NAME; // 设置窗口类名
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 设置背景色为窗口颜色
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 加载默认箭头光标
// 注册窗口类,如果失败则返回0
if (!RegisterClass(&wc)) {
MessageBox(NULL, L"窗口类注册失败!", L"错误", MB_OK | MB_ICONERROR);
return 0;
}
/* 第二步:创建窗口 */
hInst = hInstance; // 保存实例句柄到全局变量
// 创建窗口函数
HWND hwnd = CreateWindowEx(
0, // 扩展窗口样式(0表示无特殊样式)
CLASS_NAME, // 窗口类名
L"我的第一个Windows程序", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口样式:标准窗口,有标题栏、边框、系统菜单等
// 窗口位置和大小
CW_USEDEFAULT, CW_USEDEFAULT, // 左上角位置(使用默认值)
400, 300, // 宽度和高度(单位:像素)
NULL, // 父窗口句柄(无父窗口)
NULL, // 菜单句柄(无菜单)
hInstance, // 程序实例句柄
NULL // 额外创建参数
);
// 检查窗口是否创建成功
if (hwnd == NULL) {
MessageBox(NULL, L"窗口创建失败!", L"错误", MB_OK | MB_ICONERROR);
return 0;
}
/* 第三步:显示和更新窗口 */
ShowWindow(hwnd, nCmdShow); // 显示窗口
UpdateWindow(hwnd); // 更新窗口,发送WM_PAINT消息
/* 第四步:消息循环 */
MSG msg = {0}; // 消息结构体
// GetMessage从消息队列中获取消息
// 当获取到WM_QUIT消息时返回0,循环结束
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); // 翻译键盘消息
DispatchMessage(&msg); // 将消息分发到窗口处理函数
}
return (int)msg.wParam; // 程序退出代码
}
/* 第五步:窗口过程函数 – 处理所有发送到窗口的消息 */
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/* 学习笔记:Windows程序基于消息驱动机制
* 系统、用户或其他程序通过发送消息与窗口通信
* 窗口过程函数需要处理各种消息
*/
switch (uMsg) // 根据消息类型进行不同的处理
{
/* WM_DESTROY消息:窗口被销毁时发送 */
case WM_DESTROY:
PostQuitMessage(0); // 向消息队列发送WM_QUIT消息,退出消息循环
return 0;
/* WM_PAINT消息:窗口需要重绘时发送 */
case WM_PAINT:
{
PAINTSTRUCT ps; // 绘图结构体
HDC hdc = BeginPaint(hwnd, &ps); // 开始绘图,获取设备上下文
// 在窗口中绘制文本
TextOut(hdc, 100, 100, L"Hello, Windows编程!", 20);
EndPaint(hwnd, &ps); // 结束绘图
return 0;
}
/* WM_CLOSE消息:用户尝试关闭窗口时发送 */
case WM_CLOSE:
// 默认行为是直接销毁窗口,这里我们可以自定义关闭行为
if (MessageBox(hwnd, L"确定要退出程序吗?", L"确认",
MB_OKCANCEL | MB_ICONQUESTION) == IDOK) {
DestroyWindow(hwnd); // 销毁窗口
}
return 0;
/* WM_SIZE消息:窗口大小改变时发送 */
case WM_SIZE:
// 这里可以添加窗口大小改变时的处理代码
InvalidateRect(hwnd, NULL, TRUE); // 标记整个窗口需要重绘
return 0;
/* WM_LBUTTONDOWN消息:鼠标左键在窗口内按下时发送 */
case WM_LBUTTONDOWN:
{
int xPos = LOWORD(lParam); // 鼠标X坐标
int yPos = HIWORD(lParam); // 鼠标Y坐标
wchar_t message[100];
wsprintf(message, L"鼠标点击位置: (%d, %d)", xPos, yPos);
MessageBox(hwnd, message, L"鼠标事件", MB_OK);
return 0;
}
}
/* 对于未处理的消息,调用默认的窗口过程函数 */
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
五、代码详解
1. Windows程序的基本结构
包含头文件 → 声明全局变量和函数 → WinMain函数 → 消息处理函数
2. 关键概念解析
句柄(Handle)
-
操作系统用来标识和访问对象的整数值
-
如:窗口句柄(HWND)、设备上下文句柄(HDC)、实例句柄(HINSTANCE)
-
类似于文件描述符,是资源的引用
消息(Message)
-
Windows程序是事件驱动的
-
系统将用户输入、系统事件等封装成消息
-
消息放入应用程序的消息队列
-
程序通过消息循环处理消息
窗口过程(Window Procedure)
-
每个窗口都有一个窗口过程函数
-
系统调用此函数来处理窗口消息
-
类似于回调函数
3. 常见消息类型
|
WM_CREATE |
窗口创建时 |
初始化工作 |
|
WM_PAINT |
窗口需要重绘 |
绘制界面 |
|
WM_SIZE |
窗口大小改变 |
调整布局 |
|
WM_COMMAND |
菜单/按钮点击 |
执行相应操作 |
|
WM_CLOSE |
关闭窗口 |
清理资源,退出程序 |
|
WM_DESTROY |
窗口销毁 |
发送退出消息 |
六、MessageBox函数概述
1 基本概念
MessageBox是Windows API中最常用的对话框函数之一,用于显示一个简单的模态对话框,包含:
-
消息内容
-
标题
-
图标
-
按钮
-
可选的声音提示
2 函数原型
int MessageBox(
HWND hWnd, // 父窗口句柄,可以为NULL
LPCTSTR lpText, // 要显示的消息文本
LPCTSTR lpCaption, // 对话框标题
UINT uType // 对话框样式标志
);
3 uType参数完整列表(按类别)
|
按钮 |
MB_OK |
0x00000000L |
确定按钮 |
|
MB_OKCANCEL |
0x00000001L |
确定和取消按钮 |
|
|
MB_ABORTRETRYIGNORE |
0x00000002L |
终止、重试和忽略按钮 |
|
|
MB_YESNOCANCEL |
0x00000003L |
是、否和取消按钮 |
|
|
MB_YESNO |
0x00000004L |
是和否按钮 |
|
|
MB_RETRYCANCEL |
0x00000005L |
重试和取消按钮 |
|
|
MB_CANCELTRYCONTINUE |
0x00000006L |
取消、重试和继续按钮 |
|
|
图标 |
MB_ICONERROR |
0x00000010L |
错误图标 |
|
MB_ICONQUESTION |
0x00000020L |
问号图标 |
|
|
MB_ICONWARNING |
0x00000030L |
警告图标 |
|
|
MB_ICONINFORMATION |
0x00000040L |
信息图标 |
|
|
默认按钮 |
MB_DEFBUTTON1 |
0x00000000L |
第一个按钮默认 |
|
MB_DEFBUTTON2 |
0x00000100L |
第二个按钮默认 |
|
|
MB_DEFBUTTON3 |
0x00000200L |
第三个按钮默认 |
|
|
MB_DEFBUTTON4 |
0x00000300L |
第四个按钮默认 |
|
|
其他 |
MB_HELP |
0x00004000L |
添加帮助按钮 |
|
MB_SETFOREGROUND |
0x00010000L |
设为前台窗口 |
|
|
MB_DEFAULT_DESKTOP_ONLY |
0x00020000L |
仅默认桌面 |
|
|
MB_TOPMOST |
0x00040000L |
窗口置顶 |
|
|
MB_RIGHT |
0x00080000L |
文本右对齐 |
|
|
MB_RTLREADING |
0x00100000L |
从右到左阅读 |
七、ShowWindow函数详解
1. 基本定义
ShowWindow是Windows API中用于控制窗口显示状态的函数,它可以显示、隐藏、最小化、最大化或恢复窗口。
BOOL ShowWindow(
HWND hWnd, // 窗口句柄
int nCmdShow // 显示方式
);
返回值:
-
如果窗口之前可见,返回非零值(TRUE)
-
如果窗口之前隐藏,返回0(FALSE)
2. nCmdShow参数详解
/* 第一组:基本的显示/隐藏 */
SW_HIDE = 0 // 隐藏窗口
SW_SHOW = 5 // 以当前位置和大小显示窗口
SW_SHOWNORMAL = 1 // 显示并激活窗口,恢复原始大小和位置
SW_SHOWMINIMIZED = 2 // 显示并最小化窗口
SW_SHOWMAXIMIZED = 3 // 显示并最大化窗口
SW_SHOWMINNOACTIVE = 7 // 最小化显示,保持当前活动窗口不变
SW_SHOWNA = 8 // 以当前状态显示,不激活
SW_SHOWNOACTIVATE = 4 // 以最近的大小和位置显示,不激活
/* 第二组:状态切换 */
SW_MINIMIZE = 6 // 最小化窗口
SW_MAXIMIZE = 3 // 最大化窗口(同SW_SHOWMAXIMIZED)
SW_RESTORE = 9 // 恢复为原始大小和位置
/* 第三组:特殊用途 */
SW_SHOWDEFAULT = 10 // 按进程的STARTUPINFO结构显示
SW_FORCEMINIMIZE = 11 // 强制最小化,即使窗口不响应
在Windows编程中,ShowWindow(hwnd, nCmdShow);这里的 nCmdShow是 WinMain函数的最后一个参数。当Windows启动一个程序时,会根据启动方式(如正常启动、最小化启动、最大化启动等)传递一个参数给 WinMain,这个参数就是 nCmdShow,它指示了窗口初始的显示状态。
在 WinMain函数中,我们通常将这个参数传递给 ShowWindow函数,以便按照用户或系统的要求显示窗口。





