Win32 API 窗口创建实战从 WinMain 到消息循环的 7 步完整流程1. 理解 Win32 程序的基本结构Windows GUI 程序与控制台程序的核心差异在于消息驱动机制。每个 Win32 窗口程序都遵循特定的生命周期// 最小化 Win32 程序结构 #include windows.h LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);关键组件对比组件控制台程序Win32 GUI程序入口函数main()WinMain()执行方式线性执行事件驱动用户交互命令行窗口消息典型应用工具类程序图形界面软件2. 注册窗口类定义窗口行为窗口类是创建窗口的模板需要先注册后使用WNDCLASS wc {0}; wc.lpfnWndProc WindowProc; // 窗口过程函数 wc.hInstance hInstance; // 程序实例句柄 wc.lpszClassName MyWindowClass; // 类名 // 设置窗口视觉属性 wc.hbrBackground (HBRUSH)(COLOR_WINDOW1); wc.style CS_HREDRAW | CS_VREDRAW; // 窗口尺寸变化时重绘 RegisterClass(wc); // 注册到系统关键参数解析CS_HREDRAW | CS_VREDRAW窗口水平/垂直变化时触发重绘COLOR_WINDOW1使用系统默认窗口背景色类名必须是唯一标识符通常用GUID或项目特定字符串3. 创建窗口实例HWND hWnd CreateWindow( MyWindowClass, // 已注册的类名 我的第一个窗口, // 标题栏文本 WS_OVERLAPPEDWINDOW, // 窗口样式 CW_USEDEFAULT, CW_USEDEFAULT, // 初始位置 800, 600, // 宽高尺寸 NULL, // 父窗口句柄 NULL, // 菜单句柄 hInstance, // 程序实例 NULL // 创建参数 );常用窗口样式组合样式宏效果描述WS_OVERLAPPEDWINDOW标准可调整窗口含标题栏、边框、控制按钮WS_POPUP无边框弹出窗口WS_CHILD子窗口必须指定父窗口WS_VISIBLE创建后立即显示提示CW_USEDEFAULT让系统决定默认位置/尺寸适合主窗口初始化4. 显示与更新窗口ShowWindow(hWnd, nCmdShow); // nCmdShow 来自WinMain参数 UpdateWindow(hWnd); // 强制立即重绘显示模式参数示例参数值效果SW_SHOWNORMAL正常显示激活状态SW_HIDE隐藏窗口SW_MAXIMIZE最大化显示SW_MINIMIZE最小化到任务栏5. 实现消息处理函数LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); // 触发程序退出 return 0; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hWnd, ps); // 在此添加绘图代码 EndPaint(hWnd, ps); return 0; } default: return DefWindowProc(hWnd, uMsg, wParam, lParam); // 默认处理 } }常见消息处理模式// 处理鼠标左键点击 case WM_LBUTTONDOWN: { int xPos GET_X_LPARAM(lParam); int yPos GET_Y_LPARAM(lParam); // 处理点击逻辑... return 0; } // 处理键盘输入 case WM_KEYDOWN: if (wParam VK_ESCAPE) DestroyWindow(hWnd); return 0;6. 建立消息循环MSG msg; while (GetMessage(msg, NULL, 0, 0)) { TranslateMessage(msg); // 转换键盘消息 DispatchMessage(msg); // 分发到窗口过程 } return (int)msg.wParam; // 返回退出码消息循环的三种变体基础模式如上适合大多数GUI程序加速键处理HACCEL hAccel LoadAccelerators(hInstance, MyAccel); while (GetMessage(msg, NULL, 0, 0)) { if (!TranslateAccelerator(hWnd, hAccel, msg)) { TranslateMessage(msg); DispatchMessage(msg); } }非阻塞检查while (true) { if (PeekMessage(msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message WM_QUIT) break; TranslateMessage(msg); DispatchMessage(msg); } else { // 空闲时处理后台任务 } }7. 完整可运行示例代码#include windows.h LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { // 1. 注册窗口类 WNDCLASS wc {0}; wc.style CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc WndProc; wc.hInstance hInstance; wc.hCursor LoadCursor(NULL, IDC_ARROW); wc.lpszClassName TEXT(MainWindow); if (!RegisterClass(wc)) return 0; // 2. 创建窗口 HWND hWnd CreateWindow( TEXT(MainWindow), TEXT(Win32窗口示例), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); if (!hWnd) return 0; // 3. 显示窗口 ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd); // 4. 消息循环 MSG msg; while (GetMessage(msg, NULL, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } return (int)msg.wParam; } // 5. 窗口过程 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hWnd, ps); RECT rect; GetClientRect(hWnd, rect); DrawText(hdc, TEXT(Hello, Win32!), -1, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hWnd, ps); return 0; } case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd, message, wParam, lParam); } }高级技巧错误处理与调试在开发过程中添加错误检查// 创建窗口失败时显示错误信息 if (!hWnd) { DWORD err GetLastError(); LPVOID msgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPTSTR)msgBuf, 0, NULL); MessageBox(NULL, (LPCTSTR)msgBuf, TEXT(错误), MB_ICONERROR); LocalFree(msgBuf); return 1; }调试输出到控制台AllocConsole(); // 创建控制台窗口 freopen(CONOUT$, w, stdout); printf(调试信息: %d\n, someValue);