Windows API 编程是直接调用操作系统提供的函数来创建和管理 Windows 应用程序,这让你能够深入理解 Windows 的工作原理,并创建出功能强大、高度定制化的程序。

目录
-
基础概念
- 什么是 Windows API?
- 程序的入口点:
WinMain - 核心数据结构:
HANDLE和HWND - 程序的生命周期:消息循环
-
第一个 Windows 程序:经典 "Hello, Windows!"
- 代码详解
- 编译和运行
-
核心概念详解
- 窗口类:
WNDCLASS/WNDCLASSEX - 窗口创建:
RegisterClassEx和CreateWindowEx - 消息处理:
WndProc函数和switch-case结构 - 绘图:
WM_PAINT消息和BeginPaint/EndPaint - 显示窗口:
ShowWindow和UpdateWindow - 消息循环:
GetMessage,TranslateMessage,DispatchMessage
- 窗口类:
-
进阶主题
(图片来源网络,侵删)- 资源:图标、光标、菜单
- 用户输入:处理鼠标和键盘消息
- 对话框:使用资源编辑器创建对话框
- 通用控件:按钮、编辑框、列表框等
-
推荐工具和资源
基础概念
什么是 Windows API?
Windows API (Application Programming Interface) 是微软为 Windows 操作系统提供的一套庞大而复杂的函数、宏、结构体和消息的集合,你可以把它想象成一套“工具箱”,里面的每个工具(函数)都能帮你完成特定的任务,比如创建窗口、绘制图形、读写文件等。
程序的入口点:WinMain
与控制台程序从 main 函数开始不同,GUI (图形用户界面) 程序的入口点是 WinMain,它的原型如下:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
HINSTANCE hInstance: 当前模块的实例句柄,可以理解为程序自身的“身份证号”。HINSTANCE hPrevInstance: 在 32/64 位 Windows 中,这个参数总是NULL,可以忽略。LPSTR lpCmdLine: 命令行参数,字符串形式。int nCmdShow: 指定窗口如何显示(正常显示、最大化、最小化)。
核心数据结构:HANDLE 和 HWND
Windows API 大量使用句柄,句柄是一个唯一的标识符,由系统在创建对象(如窗口、文件、画笔)时返回,你的程序通过这个句柄来操作该对象,而不是直接操作对象本身。

HWND: Handle to a Window (窗口句柄),所有窗口操作都离不开它。HINSTANCE: Handle to an Instance (实例句柄)。HDC: Handle to a Device Context (设备上下文句柄),用于在窗口上绘图。
程序的生命周期:消息循环
Windows 程序是事件驱动的,程序大部分时间都在一个循环中等待,等待用户或系统发送消息(如鼠标点击、键盘按下、窗口需要重绘等),程序接收到消息后,会调用一个专门的函数来处理它,然后继续等待,这个循环就是消息循环。
第一个 Windows 程序:经典 "Hello, Windows!"
这是一个完整的、最简单的 Windows GUI 程序,它创建一个窗口,并在窗口客户区显示 "Hello, Windows!"。
#include <windows.h>
// 1. 窗口过程函数的声明
// 这个函数负责处理发送到该窗口的所有消息
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// 2. WinMain 函数 - 程序的入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// 3. 定义并初始化窗口类
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW; // 窗口大小改变时重绘
wcex.lpfnWndProc = WndProc; // 指向窗口过程函数的指针
wcex.hInstance = hInstance; // 程序实例句柄
wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // 使用标准箭头光标
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 使用默认窗口背景色
wcex.lpszClassName = "MyWindowClass"; // 窗口类名
// 4. 注册窗口类
if (!RegisterClassEx(&wcex)) {
MessageBox(NULL, "窗口类注册失败!", "错误", MB_ICONERROR);
return 1;
}
// 5. 创建窗口
HWND hWnd = CreateWindowEx(
0, // 扩展样式
"MyWindowClass", // 窗口类名
"我的第一个窗口", // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口样式
CW_USEDEFAULT, CW_USEDEFAULT, // x, y 坐标 (由系统决定)
500, 400, // 宽度和高度
NULL, // 父窗口句柄
NULL, // 菜单句柄
hInstance, // 程序实例句柄
NULL // 创建参数
);
if (!hWnd) {
MessageBox(NULL, "窗口创建失败!", "错误", MB_ICONERROR);
return 1;
}
// 6. 显示窗口
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd); // 立即发送一个 WM_PAINT 消息
// 7. 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); // 翻译键盘消息
DispatchMessage(&msg); // 将消息发送到 WndProc 函数
}
// 8. 程序结束,返回消息码
return (int)msg.wParam;
}
// 9. 窗口过程函数 - 定义窗口的行为
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR* greeting = TEXT("Hello, Windows!");
switch (message) {
case WM_PAINT: {
// 当窗口需要重绘时,系统会发送此消息
hdc = BeginPaint(hWnd, &ps);
// 在窗口上绘制文本
TextOut(hdc, 50, 50, greeting, lstrlen(greeting));
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY: {
// 当用户点击窗口的关闭按钮时,系统会发送此消息
PostQuitMessage(0); // 发送 WM_QUIT 消息,退出消息循环
break;
}
default:
// 对于我们没有处理的消息,交给系统默认处理
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
代码详解
WndProc声明: 在WinMain之前声明,因为WinMain需要它的地址。WinMain: 主函数,负责程序的整体流程。WNDCLASSEX: 结构体,用来定义窗口的“模板”,包括窗口的图标、光标、背景色、最重要的——处理消息的函数WndProc。RegisterClassEx: 向操作系统“注册”我们定义好的窗口类,注册成功后,才能用这个类名来创建窗口。CreateWindowEx: 根据已注册的窗口类名,创建一个具体的窗口实例,这个函数返回窗口的句柄hWnd。ShowWindow: 创建窗口后,它默认是不可见的,这个函数让窗口显示出来。UpdateWindow: 强制窗口立即进行一次重绘,确保窗口内容一开始就是正确的。MSG msg; while(GetMessage(...)): 这就是消息循环的核心。GetMessage从消息队列中取出一个消息,如果没有消息,它会阻塞程序。TranslateMessage和DispatchMessage负责处理和分发消息。WndProc: 这是程序的心脏。DispatchMessage会把消息的详细信息(hWnd,message,wParam,lParam)传递给这个函数,我们通过switch-case来响应不同的消息。WM_PAINT: 绘制消息,当窗口第一次显示、被其他窗口遮挡后又显示、或大小改变时,系统会发送这个消息,我们在这里调用BeginPaint开始绘图,TextOut绘制文本,EndPaint结束绘图。WM_DESTROY: 销毁消息,当用户点击关闭按钮时发送,我们在这里调用PostQuitMessage(0),它会向消息循环中注入一个WM_QUIT消息,导致GetMessage返回FALSE,从而退出循环,程序结束。default: 如果我们不处理某个消息(比如鼠标移动),就调用DefWindowProc,让系统执行默认操作。
核心概念详解
窗口类 (WNDCLASSEX)
窗口类是创建窗口的蓝图,你可以定义一个窗口类,然后用它创建多个窗口实例(比如记事本程序,一个主窗口和一个查找替换的对话框窗口)。
窗口创建 (RegisterClassEx 和 CreateWindowEx)
- 注册:
RegisterClassEx告诉 Windows:“我有一个叫 'MyWindowClass' 的窗口类,它长这样,处理消息的方式是WndProc”。 - 实例化:
CreateWindowEx基于这个蓝图,创建一个具体的、可见的窗口对象,并返回它的句柄hWnd。
消息处理 (WndProc)
WndProc 是一个回调函数,意味着 Windows 会在需要的时候调用它,而不是你直接调用它,它决定了你的窗口如何响应各种事件。
绘图 (WM_PAINT 和设备上下文 HDC)
- WM_PAINT: 这是窗口进行“自我描绘”的信号,你不能随意在任何地方绘图,而应该在响应
WM_PAINT消息时进行。 - HDC (Device Context): 设备上下文是一个“绘图工具包”,它包含了所有关于绘图环境的信息(如选中的画笔、字体、颜色等)。
BeginPaint会为WM_PAINT消息准备一个HDC,EndPaint则负责清理,你使用这个HDC里的函数(如TextOut,LineTo,Rectangle)来绘制。
进阶主题
资源
图标、光标、位图、菜单等都是资源,它们通常存储在 .rc 文件中,并由资源编译器编译进 .exe 文件里,你可以使用 Visual Studio 自带的资源视图来可视化地创建和管理它们。
用户输入
除了 WM_PAINT,你还需要处理:
WM_LBUTTONDOWN: 鼠标左键按下。WM_KEYDOWN: 键盘按键按下。- 在
WndProc的switch语句中添加相应的case即可。
对话框
对话框是一种特殊的预定义窗口,你可以通过资源编辑器设计对话框布局(包含按钮、文本框等),然后通过 DialogBox 函数来创建和显示它。
通用控件
Windows 提供了丰富的标准控件,如按钮 (BUTTON)、编辑框 (EDIT)、列表框 (LISTBOX) 等,创建它们通常需要:
- 在窗口类中指定一个菜单资源(或者使用对话框)。
- 在
WM_CREATE消息中,使用CreateWindowEx并指定控件的类名(如"BUTTON")来创建它们。
推荐工具和资源
开发环境
- Visual Studio (推荐): 最简单、最强大的选择,它集成了编译器、链接器、资源编辑器和强大的调试器,创建项目时选择 "Windows 桌面应用程序" 模板即可。
- MinGW (Minimalist GNU for Windows): 如果你喜欢轻量级的命令行工具,可以使用 MinGW,配合像 Dev-C++ 或 Code::Blocks 这样的 IDE 使用。
学习资源
- Charles Petzold 的《Windows 程序设计》: 这本书被誉为 Windows API 编程的“圣经”,非常经典和详尽。
- Microsoft 官方文档: MSDN (Microsoft Developer Network) 是最权威的参考资料,几乎所有 API 函数、结构体、消息都有详细说明。
- 在线教程: 搜索 "Windows API tutorial C" 可以找到很多优秀的入门教程。
希望这份指南能帮助你顺利开启 Windows API 编程之旅!从理解 WinMain 和 WndProc 开始,逐步探索消息机制和绘图,你会发现一个强大的 Windows 编程世界。
