一、题目运行Windows应用程序在桌面显示Windows窗口。窗口内背景色为灰色且窗口中居中显示“大家好这是我的第一个Windows API程序”同时播放背景音乐并可通过程序改变窗口显示风格为只有标题栏以及鼠标指针形状为手型。二、源代码#include windows.h #include string #include mmsystem.h #pragma comment(lib, winmm.lib) #define ID_BTN_STYLE 1001 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hBtn NULL; static bool bTitleOnly false; switch (uMsg) { case WM_CREATE: hBtn CreateWindow( LBUTTON, L切换窗口风格, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 20, 150, 30, hwnd, (HMENU)ID_BTN_STYLE, ((LPCREATESTRUCT)lParam)-hInstance, NULL); return 0; case WM_COMMAND: if (LOWORD(wParam) ID_BTN_STYLE) { bTitleOnly !bTitleOnly; LONG_PTR style GetWindowLongPtr(hwnd, GWL_STYLE); if (bTitleOnly) style WS_CAPTION | WS_SYSMENU | WS_VISIBLE; // ← 加 WS_VISIBLE else style WS_OVERLAPPEDWINDOW | WS_VISIBLE; // ← 也加上 SetWindowLongPtr(hwnd, GWL_STYLE, style); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); InvalidateRect(hwnd, NULL, TRUE); // 让整个客户区作废重绘 UpdateWindow(hwnd); // 立即重绘 } return 0; case WM_SIZE: { // 让整个客户区重绘 InvalidateRect(hwnd, NULL, TRUE); // 根据窗口大小重新摆放按钮 if (hBtn) { int cx LOWORD(lParam); // 客户区宽度 int cy HIWORD(lParam); // 客户区高度 // 按钮宽高按客户区比例算 int btnW cx / 4; int btnH cy / 10; if (btnW 80) btnW 80; if (btnH 24) btnH 24; // 按钮放在左上角边距按比例 int margin cx / 40; MoveWindow(hBtn, margin, margin, btnW, btnH, TRUE); } return 0; } case WM_CLOSE: PlaySound(NULL, NULL, 0); // 关窗口前先掐掉声音 DestroyWindow(hwnd); // 手动销毁窗口 return 0; case WM_DESTROY: PlaySound(NULL, NULL, 0); // 再停一次保险 PostQuitMessage(0); return 0; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hwnd, ps); HBRUSH hBrush CreateSolidBrush(RGB(192, 192, 192)); FillRect(hdc, ps.rcPaint, hBrush); DeleteObject(hBrush); SetTextColor(hdc, RGB(0, 0, 0)); SetBkMode(hdc, TRANSPARENT); RECT rect; GetClientRect(hwnd, rect); // 按窗口宽度的 1/20 算字号范围限制在 16~72 int fontSize (rect.right - rect.left) / 20; if (fontSize 16) fontSize 16; if (fontSize 72) fontSize 72; HFONT hFont CreateFont(fontSize, 0, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, L微软雅黑); HFONT hOld (HFONT)SelectObject(hdc, hFont); const std::wstring text L大家好这是我的第一个Windows API程序; DrawTextW(hdc, text.c_str(), -1, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); SelectObject(hdc, hOld); DeleteObject(hFont); EndPaint(hwnd, ps); return 0; } case WM_SETCURSOR: { if (LOWORD(lParam) HTCLIENT) { SetCursor(LoadCursor(NULL, IDC_HAND)); return TRUE; } break; } } return DefWindowProc(hwnd, uMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { PlaySound(TEXT(hellowin.wav), NULL, SND_ASYNC | SND_FILENAME ); const wchar_t CLASS_NAME[] LSample Window Class; WNDCLASS wc {}; wc.lpfnWndProc WindowProc; wc.hInstance hInstance; wc.lpszClassName CLASS_NAME; RegisterClass(wc); int screenWidth GetSystemMetrics(SM_CXSCREEN); int screenHeight GetSystemMetrics(SM_CYSCREEN); const int windowWidth 500; const int windowHeight 400; int startX (screenWidth - windowWidth) / 2; int startY (screenHeight - windowHeight) / 2; HWND hwnd CreateWindowEx( 0, CLASS_NAME, L我的第一个Windows API程序, WS_OVERLAPPEDWINDOW, startX, startY, windowWidth, windowHeight, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd, nShowCmd); UpdateWindow(hwnd); MSG msg; while (GetMessage(msg, nullptr, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); } return 0; }三、源代码思路解析1 头文件与库#include windows.h // Windows API 基础 #include string // std::wstring #include mmsystem.h // PlaySound 等多媒体 API #pragma comment(lib, winmm.lib) // 链接 winmm.libmmsystem.h提供PlaySound声明#pragma comment让链接器自动链接winmm.lib无需手动在项目属性中添加。2 窗口过程函数 WindowProcWindowProc是窗口的消息处理核心所有发往该窗口的消息都在这里分发处理。1WM_CREATE创建按钮case WM_CREATE: hBtn CreateWindow( LBUTTON, L切换窗口风格, WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 20, 150, 30, hwnd, (HMENU)ID_BTN_STYLE, ((LPCREATESTRUCT)lParam)-hInstance, NULL); return 0;窗口创建时在客户区左上角创建一个子按钮。WS_CHILD | WS_VISIBLE表示它是可见的子窗口BS_PUSHBUTTON是普通按钮样式。按钮 ID 为ID_BTN_STYLE供WM_COMMAND识别。2WM_COMMAND响应按钮切换窗口风格case WM_COMMAND: if (LOWORD(wParam) ID_BTN_STYLE) { bTitleOnly !bTitleOnly; LONG_PTR style GetWindowLongPtr(hwnd, GWL_STYLE); if (bTitleOnly) style WS_CAPTION | WS_SYSMENU | WS_VISIBLE; else style WS_OVERLAPPEDWINDOW | WS_VISIBLE; SetWindowLongPtr(hwnd, GWL_STYLE, style); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } return 0;GetWindowLongPtr(hwnd, GWL_STYLE)取出当前窗口风格位。WS_CAPTION | WS_SYSMENU表示只有标题栏和关闭按钮无边框、无最大化最小化。WS_OVERLAPPEDWINDOW恢复为普通可缩放窗口。关键点必须加WS_VISIBLE否则整体替换风格位时会把可见标志抹掉导致窗口进入逻辑不可见状态按钮失灵。SetWindowPos(..., SWP_FRAMECHANGED)让新边框立即生效。InvalidateRect(hwnd, NULL, TRUE)UpdateWindow强制整个客户区重绘避免切换风格后残留旧图像。3WM_SIZE尺寸变化时全客户区重绘case WM_SIZE: InvalidateRect(hwnd, NULL, TRUE); return 0;最大化、还原、拖边框等操作会触发WM_SIZE。这里让整个客户区作废并重绘防止文字残影。4WM_CLOSE关闭前停止音乐case WM_CLOSE: PlaySound(NULL, NULL, 0); DestroyWindow(hwnd); return 0;先停止音乐再手动调用DestroyWindow销毁窗口。因为接管了WM_CLOSE默认销毁逻辑不再执行必须自己调用DestroyWindow。5WM_DESTROY退出消息循环case WM_DESTROY: PlaySound(NULL, NULL, 0); PostQuitMessage(0); return 0;PostQuitMessage(0)向消息队列投递WM_QUIT使WinMain中的GetMessage返回 0退出消息循环进程结束。6WM_PAINT绘制背景与文字case WM_PAINT: { PAINTSTRUCT ps; HDC hdc BeginPaint(hwnd, ps); HBRUSH hBrush CreateSolidBrush(RGB(192, 192, 192)); FillRect(hdc, ps.rcPaint, hBrush); DeleteObject(hBrush); SetTextColor(hdc, RGB(0, 0, 0)); SetBkMode(hdc, TRANSPARENT); RECT rect; GetClientRect(hwnd, rect); const std::wstring text L大家好这是我的第一个Windows API程序; DrawTextW(hdc, text.c_str(), -1, rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, ps); return 0; }BeginPaint/EndPaint成对使用获取和释放设备上下文。CreateSolidBrush(RGB(192,192,192))创建灰色画刷FillRect填充客户区。SetBkMode(TRANSPARENT)让文字背景透明避免出现文字底色框。GetClientRect获取客户区矩形配合DT_CENTER | DT_VCENTER实现水平垂直居中。不使用DT_NOCLIP防止文字被绘制到区域外产生残影。7WM_SETCURSOR手型光标case WM_SETCURSOR: { if (LOWORD(lParam) HTCLIENT) { SetCursor(LoadCursor(NULL, IDC_HAND)); return TRUE; } break; }lParam低字为命中测试码。若鼠标位于客户区HTCLIENT把光标设为手型并返回TRUE表示消息已处理否则交给DefWindowProc处理例如边框上的缩放光标。3 入口函数 WinMainPlaySound(TEXT(hellowin.wav), NULL, SND_ASYNC | SND_FILENAME);SND_FILENAME表示第一个参数是文件名。SND_ASYNC异步播放不阻塞主线程。不加SND_LOOP因此只播放一次适合开机音效。WNDCLASS wc {}; wc.lpfnWndProc WindowProc; wc.hInstance hInstance; wc.lpszClassName CLASS_NAME; RegisterClass(wc);注册窗口类指定窗口过程、实例句柄和类名。int screenWidth GetSystemMetrics(SM_CXSCREEN); int screenHeight GetSystemMetrics(SM_CYSCREEN); int startX (screenWidth - windowWidth) / 2; int startY (screenHeight - windowHeight) / 2;通过GetSystemMetrics取屏幕宽高计算窗口左上角坐标使窗口在屏幕上居中。HWND hwnd CreateWindowEx( 0, CLASS_NAME, L我的第一个Windows API程序, WS_OVERLAPPEDWINDOW, startX, startY, windowWidth, windowHeight, NULL, NULL, hInstance, NULL);创建窗口初始风格为WS_OVERLAPPEDWINDOW普通可缩放窗口。MSG msg; while (GetMessage(msg, nullptr, 0, 0)) { TranslateMessage(msg); DispatchMessage(msg); }标准消息循环GetMessage取消息TranslateMessage翻译键盘消息DispatchMessage将消息分发到WindowProc。当收到WM_QUIT时循环结束程序退出。四、遇到的问题以及解决方案问题 1无法解析的外部符号 main这两个错误连在一起看原因很明确LNK2019: 无法解析的外部符号 main→链接器在找main函数说明当前是控制台子系统LNK1120: 1 个无法解析的外部命令→ 上面那个错误的连带结果也就是说项目被设成了控制台 (/SUBSYSTEM:CONSOLE)但代码里写的是WinMain链接器找不到main就报错。至于那个C28251警告WinMain注释不一致只是警告不是致命错误可以先不管。解决办法改子系统项目 → 属性或右键项目 → 属性→配置属性 → 链接器 → 系统→ 把子系统从控制台 (/SUBSYSTEM:CONSOLE)改成窗口 (/SUBSYSTEM:WINDOWS)→ 确定 → 重新生成。改完后重新按CtrlShiftB生成应该就没这两个链接错误了。顺手确认另外两项避免改完又出新错① 字符集项目 → 属性 → 配置属性 →高级 → 字符集→ 选使用 Unicode 字符集。代码里用了std::wstring、L...、DrawTextW必须是 Unicode。如果是多字节字符集L...和DrawTextW会有类型不匹配的错。② 入口点一般不用改如果改成窗口子系统后链接器又报WinMain找不到那就再设一下入口点项目 → 属性 → 链接器 →高级 → 入口点→ 填WinMainCRTStartup。正常情况下改成窗口子系统后MSVC 会自动匹配WinMain不需要手动设入口点。正确状态成功生成exe文件问题 2关闭窗口后音乐仍在播放现象点击窗口右上角 × 后窗口关闭但开机音效仍在循环播放orz。原因一开始代码只在WM_DESTROY里调用PlaySound(NULL,NULL,0)且播放时带了SND_LOOP停止不够及时。另外当时项目里可能残留了多个 exe 进程。解决播放时去掉SND_LOOP改为只播放一次。在WM_CLOSE里也调用PlaySound(NULL, NULL, 0)先停声再销毁窗口。WM_DESTROY里再次停止形成双保险。用任务管理器清理所有残留的Project1.exe进程。问题 3点击切换窗口风格后窗口卡住、按钮失灵现象点击按钮后窗口变成只有标题栏但按钮无法再点击整个界面像卡死。原因切换风格时用style WS_CAPTION | WS_SYSMENU;整体替换了窗口风格位把WS_VISIBLE可见标志一并抹掉窗口进入不可见但未销毁的状态子按钮随之异常。解决在切换风格时补回WS_VISIBLEstyle WS_CAPTION | WS_SYSMENU | WS_VISIBLE; style WS_OVERLAPPEDWINDOW | WS_VISIBLE;或者更稳妥地只修改需要改的风格位而不整体替换。问题 4全屏后或者变动窗口出现两个大家好文字残影现象最大化窗口或还原后客户区同时出现两个大家好……居中那个是正常的另一个是旧图像的残留。原因DrawTextW使用了DT_NOCLIP允许文字绘制到矩形区域之外。WM_PAINT中FillRect只填充ps.rcPaint系统指定的重绘区域未覆盖的部分保留旧内容。窗口尺寸变化时未强制全客户区重绘。解决去掉DT_NOCLIP让文字被限制在rect内。在WM_SIZE消息中调用InvalidateRect(hwnd, NULL, TRUE)使尺寸变化时整个客户区作废重绘。在切换风格后同样调用InvalidateRect UpdateWindow。五、最终实现效果起始效果切换窗口风格全屏效果任意尺寸六、实验总结本次实验完整地实现了一个具备多项功能的 Win32 窗口程序主要收获如下理解了 Windows 消息驱动机制。窗口的一切行为绘制、点击、尺寸变化、关闭都由消息触发WindowProc是处理消息的核心GetMessage/DispatchMessage构成消息循环。掌握了 GDI 绘图基本方法。使用BeginPaint/EndPaint、FillRect、DrawTextW等完成背景填充和文字居中显示。学会了动态修改窗口风格。通过GetWindowLongPtr/SetWindowLongPtr配合GWL_STYLE和SetWindowPos(SWP_FRAMECHANGED)可在运行时切换窗口外观但必须注意保留WS_VISIBLE等必要风格位。掌握了音频播放控制。PlaySound配合SND_ASYNC | SND_FILENAME可异步播放一次音频需要停止时传入NULL。认识到重绘的重要性。InvalidateRect、WM_SIZE、CS_HREDRAW/CS_VREDRAW等机制决定了窗口在尺寸变化、风格切换时能否正确重绘处理不当会出现残影。积累了调试经验。编译错误往往被运行错误掩盖应先生成解决方案确认编译通过多个 exe 进程残留会造成程序卡死的假象修改代码后必须重新生成否则运行的仍是旧 exe。本次实验让我们对 Win32 API 的编程范式和消息机制有了直观而深入的理解为后续学习更复杂的 Windows 应用开发打下了基础。
企业数字化 ERP 产品动态
相关推荐
为什么职员能工资20K?熟悉掌握了这些Python自动化办公模块 今天, 我将继续来给大家去分享一下这个自动化办公库, 而这个库是我花费了两周的时间去进行整理的。这次的这个内容, 它就是把那些库给说完了, 这些库里头, 包括了Excel、Word、PPT、ODF、PDF、邮件、微信、文件处理等所有能在办公场景实现自动化的库, 就是希望这些东西能够对大… · 2026/9/24 17:44:33
python常用内置函数大全,python内置函数有哪些 一、数学函数1.关于abs()这个函数, 它的主要作用就是帮你去取绝对值。print(abs(-10))>>>102.该函数用于在同一操作过程中, 同时获取除法运算所得到的商值以及余数值。print(divmod(7,2))>>>(3, 1)3.sum()这一函数, 它的主要功能是用来进行求和计算。li[1,2,… · 2026/9/24 17:44:33
实现,提供客户端和服务器功能 它是SSHv2协议的实现, 提供客户端和服务器功能。它本身是一个纯粹的接口, 这个接口紧密围绕着SSH网络的概念来构建。我们可以使用它, 通过这样的方式来进行ssh操作, 而且这个过程会变得相当的方便。该方案由两个核心组件构成, 具体表现为: 和。它的作用, 实际上就跟咱们平时用的… · 2026/9/24 17:44:33
Java超市积分管理系统实战:数据库设计与事务处理全解析 简介:面向Java Web学习者和高校毕设学生的超市积分管理系统完整项目资料包,以会员积分、商品管理等典型业务场景为线索,帮助读者掌握从需求分析到编码实现的全流程。压缩包仅18.21MB,共5个文件,其中sql为数据库脚本、d… · 2026/9/24 18:12:28
车载驾驶员疲劳检测实战:轻量模型+鲁棒设计+毕设落地指南 简介:本资源是一套面向计算机专业本科生的毕业设计实战项目,聚焦驾驶员疲劳状态识别这一实际安全需求,基于卷积神经网络实现人脸检测、关键特征提取与疲劳判别预警全流程。适用于正在开展毕设、课程设计或期末大作业的学生,也适合… · 2026/9/24 18:12:28
YOLO卫星遥感多类别目标检测数据集:从标注格式到训练调参全攻略 简介:YOLO卫星遥感多类别检测数据集,适合正在学习目标检测或从事遥感影像识别应用的开发者。资源围绕真实场景的高质量卫星影像构建,使用LabelImg标注,标注框规范,同时提供VOC(xml)、COCO&#… · 2026/9/24 18:12:28
2026全球锂电干燥设备行业全景解析:市场扩容、技术迭代与全球化布局机遇 锂电干燥设备是锂电池制造环节的核心工艺装备,直接决定电芯的水分控制水平,进而影响电池的循环寿命、安全性能与量产良率。随着2026年全球动力电池与储能电池产能持续扩张,锂电干燥设备行业已经从单纯的产能驱动阶段,全面进入“技… · 2026/9/24 18:12:22
asd asd sad sad asd · 2026/9/24 18:12:16
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44