Windows API程序|使用Win32 API制作带音频播放的窗口程序
Windows API程序|使用Win32 API制作带音频播放的窗口程序
📅实验时间:2026‑09‑23
🛠开发环境:Visual Studio 2022、Windows10/Windows11、C语言 Win32 API
✨实现功能:灰色背景窗口、居中文字、手型光标、隐藏最大化/最小化/关闭按钮、MCI播放wav背景音乐、ESC按键关闭窗口、资源释放与错误提示
一、实验目标
本次练习使用C语言与Windows Win32 API编写简单桌面GUI程序,理解Windows消息驱动模型,掌握窗口完整开发流程:窗口类注册、窗口创建、消息循环、窗口回调处理。
程序需要完成下面全部功能:
- 创建标题为
我的第一个Win窗口的窗口,窗口大小650×320; - 灰色客户区背景,窗口正中央显示一行中文文本;
- 鼠标移入窗口客户区显示手型光标;
- 标题栏只保留标题,不显示最小化、最大化、关闭按钮;
- 使用MCI多媒体接口播放外部
hellowin.wav音频作为背景音乐; - 按下键盘
ESC键关闭窗口;程序退出时释放音频资源; - 增加音频打开失败错误弹窗提示。
二、前置知识
Windows应用程序和控制台程序不一样,控制台程序入口是main(),Win32窗口程序入口函数为WinMain。
Windows是消息驱动机制:操作系统发生事件(鼠标移动、按键按下、窗口重绘)就会生成消息,程序通过消息循环不停获取消息,分发到窗口过程函数WndProc,在回调函数内部对不同消息做对应处理。
核心组件:
WNDCLASSEX结构体:定义窗口类,设置背景色、光标、图标、窗口过程回调函数;RegisterClassEx():向操作系统注册自定义窗口类;CreateWindowEx():根据注册好的窗口类,生成窗口实例;- 消息循环
GetMessage‑TranslateMessage‑DispatchMessage:程序的心脏,接收并转发系统消息; WndProc窗口过程回调函数:处理WM_PAINT绘图、WM_KEYDOWN键盘、WM_DESTROY销毁窗口等各类消息;- MCI接口:
mciSendString多媒体命令接口,用来打开、播放、关闭wav音频,需要链接winmm.lib库。
⚠注意:MCI原生只支持PCM编码的wav文件,其他压缩格式wav无法正常播放。
三、项目文件结构
Project1
└── x64/Debug
├─ Project1.exe //编译生成可执行程序
├─ Project1.pdb
└─ hellowin.wav //wav音频文件,放到exe同一目录
音频文件必须放在程序运行输出目录,或者代码写完整绝对路径,否则会报音频打开失败。
四、详细操作步骤
步骤1:新建VS空项目
- 打开 Visual Studio 2022,点击【创建新项目】,选择 空项目(C++),点击下一步;
- 设置项目名称(例:Project1),选择保存路径,取消“将解决方案和项目放在同一目录中”,点击创建。
步骤2:添加C++源文件
- 在右侧【解决方案资源管理器】,右键源文件 →【添加】→【新建项】;
- 选择C++文件(.cpp),文件名填写
main.cpp,点击添加; - 将完整源代码复制粘贴到main.cpp文件中。
步骤3:准备wav音频文件
- 准备PCM编码的wav音频,命名为
hellowin.wav; - 找到项目输出目录:
项目目录\x64\Debug\; - 将
hellowin.wav复制粘贴到Debug文件夹,和生成的exe放在同一级目录。
也可以直接使用绝对路径写在代码open指令内,注意Windows路径反斜杠需要写两个
\\。
步骤4:确认多媒体库链接
代码头部已经写了:
#pragma comment(lib, "winmm.lib")
这条指令作用:编译时自动链接多媒体库,不需要手动去项目属性配置链接器输入。
步骤5:修改源码编码,预防中文乱码
- VS顶部菜单栏:【文件】→【高级保存选项】;
- 编码选择 Unicode(UTF‑8带签名)‑代码页65001,点击确定保存文件。
步骤6:编译运行程序
- 平台选择
x64(不要选x86); - 点击菜单栏【生成】→【生成解决方案】;
- 编译无报错后,点击本地Windows调试器运行程序。
✅预期运行效果:
弹出灰色窗口,标题“我的第一个Win窗口”;窗口中间居中显示中文;鼠标进入窗口光标变为手型;窗口右上角没有最小化、最大化、关闭按钮;自动播放wav背景音乐;按下键盘ESC键,窗口关闭,音频资源释放。
五、完整源代码
#include <windows.h>
#include <mmsystem.h>
//链接多媒体库,提供MCI音频播放支持
#pragma comment(lib, "winmm.lib")
//窗口过程函数声明,处理全部窗口消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
//WinMain:Windows GUI程序入口,等价控制台main
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const TCHAR szClassName[] = TEXT("MyWinClass");
HWND hWnd;
MSG msg;
WNDCLASSEX wndClass;
//1.填充窗口类结构体
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_HREDRAW | CS_VREDRAW; //窗口大小改变自动重绘
wndClass.lpfnWndProc = WndProc; //绑定消息回调函数
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance; //当前程序实例句柄
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_HAND); //手型光标
wndClass.hbrBackground = (HBRUSH)(COLOR_GRAYTEXT + 1); //灰色背景
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szClassName;
wndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
//注册窗口类
RegisterClassEx(&wndClass);
//2.创建窗口
//WS_CAPTION:仅标题栏;不添加WS_SYSMENU,去掉右上角三个系统按钮
hWnd = CreateWindowEx(
0,
szClassName,
TEXT("我的第一个Win窗口"),
WS_CAPTION,
CW_USEDEFAULT,
CW_USEDEFAULT,
650,
320,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//MCI打开wav音频,设置别名music
MCIERROR mciRet = mciSendString(TEXT("open D:\\Users\\1\\source\\repos\\Project1\\x64\\Debug\\hellowin.wav alias music"), NULL, 0, NULL);
if (mciRet != 0)
{
TCHAR errBuf[256];
mciGetErrorString(mciRet, errBuf, 256);
MessageBox(hWnd, errBuf, TEXT("Audio Open Error"), MB_ICONERROR);
}
else
{
mciSendString(TEXT("set music notify on"), NULL, 0, NULL);
mciSendString(TEXT("play music"), NULL, 0, NULL);
}
//消息循环,程序主循环
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//程序退出,关闭释放音频资源
mciSendString(TEXT("close music"), NULL, 0, NULL);
return (int)msg.wParam;
}
//窗口回调过程,处理各类窗口消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
TCHAR szText[] = TEXT("大家好,这是我的第一个Windows API程序!");
switch (msg)
{
//窗口重绘消息,绘制居中文字
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rect);
//单行、水平居中、垂直居中绘制文本
DrawText(hdc, szText, lstrlen(szText), &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
return 0;
//窗口销毁,发送退出消息终止消息循环
case WM_DESTROY:
PostQuitMessage(0);
return 0;
//键盘按下消息:ESC键销毁窗口
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
{
DestroyWindow(hWnd);
}
return 0;
}
//其余未处理消息交给系统默认处理
return DefWindowProc(hWnd, msg, wParam, lParam);
}
六、实验常见问题与完整解决方案
🎵问题1:音乐播放不成功,弹出Audio Open Error报错弹窗
现象:程序运行直接弹出音频错误提示框,没有背景音乐。
产生原因分为4种:
- 文件路径错误;Windows字符串路径必须写双反斜杠
\\,单斜杠\会被识别为转义字符; hellowin.wav不在x64/Debug输出目录,exe找不到音频文件;- wav音频编码不是PCM编码,MCI接口不支持压缩格式wav;
- 文件名大小写不匹配,例如代码写hellowin.wav,实际文件是Hellowin.wav。
✅解决办法:
- 优先把wav复制到exe同一Debug文件夹;写绝对路径时确认路径,路径分隔符必须是
\\; - 查看音频属性,确认编码为PCM;如果不是,使用格式工厂转换音频编码为PCM‑wav;
- 核对文件名大小写,严格和代码内名称保持一致;
- 利用弹窗返回的错误信息定位,弹窗会直接输出MCI错误描述。
🀄问题2:窗口中文乱码,C4819编译器警告,中文变成方框问号
现象:窗口上中文文本显示乱码,VS输出窗口出现警告C4819: 该文件包含不能在当前代码页(936)中表示的字符。
原因:源代码保存编码为UTF‑8无BOM,VS编译器默认使用GBK(936代码页)解析源码,中文字符解析失败。
✅解决办法:
- VS菜单栏【文件】→【高级保存选项】;
- 编码选择:Unicode(UTF‑8带签名)‑代码页65001,点击确定保存文件;
- 全部关闭文件,重新打开,再次编译运行。
不要使用UTF‑8无BOM,VS的MSVC编译器对无BOM的UTF‑8源码中文兼容性很差。
🔨问题3:LNK1104链接错误,无法打开Project1.exe
现象:编译报错 LNK1104 无法打开文件“x64\Debug\Project1.exe”。
原因:上一次运行的窗口程序没有正常关闭,进程还驻留在内存,exe文件被进程占用,VS不能覆盖生成新可执行文件。
✅解决办法:
Ctrl+Shift+Esc打开任务管理器;- 在进程列表找到
Project1.exe,右键结束任务; - 返回VS,点击【生成】→【重新生成解决方案】。
🎶问题4:音频只播放一遍,不能循环播放
现象:背景音乐只播放一次之后静音。
原因:代码开启set music notify on,但是窗口回调函数WndProc没有处理MM_MCINOTIFY播放完成消息,音频播放结束后没有重新发起play命令。
✅拓展解决方案(实现循环播放):
在WndProc的switch增加MM_MCINOTIFY消息分支:
case MM_MCINOTIFY:
if(wParam == MCI_NOTIFY_SUCCESSFUL)
{
//播放完成,重新播放,实现循环
mciSendString(TEXT("play music notify on"),NULL,0,NULL);
}
return 0;
注意:需要把
set music notify on,play指令带上notify参数。
⌨问题5:按下ESC键窗口没有关闭
现象:敲击键盘ESC,程序窗口毫无反应。
原因:窗口没有获得焦点,键盘消息不会发送到此窗口;或者代码写错虚拟键值VK_ESCAPE。
✅解决办法:点击窗口灰色区域激活窗口焦点再按ESC;检查代码判断条件if(wParam == VK_ESCAPE),不要写错宏名。
🖼问题6:右上角还存在关闭按钮
现象:窗口右上角仍然看见关闭×按钮。
原因:创建窗口CreateWindowEx的窗口样式参数,多写了WS_SYSMENU。
✅解决办法:窗口样式只保留WS_CAPTION,删除WS_SYSMENU宏。
七、知识点总结
- Windows GUI程序基于消息驱动,
WinMain是程序入口,消息循环是程序主体,所有交互都依靠消息分发。 WNDCLASSEX用来定义窗口类,注册之后才能创建窗口实例;窗口的绘制工作写在WM_PAINT消息分支。CreateWindowEx的窗口样式参数非常关键:去掉WS_SYSMENU就可以移除右上角最小化最大化关闭按钮。- MCI多媒体接口适合简单音频播放,注意必须程序退出调用
close释放音频资源,避免资源泄露。 - Windows开发很容易遇到编码、文件路径、进程占用类问题,要充分利用弹窗报错、编译器警告信息定位问题。
📌拓展改进方向:实现音频循环播放;增加按钮控件;增加播放暂停控制;异常处理进一步完善。
复制全部内容直接粘贴到CSDN编辑器,全部Markdown语法完全兼容。如果你需要,我还可以帮你把实验报告的小结也提取出来。

浙公网安备 33010602011771号