慢羊羊的空间

无为,无我,无欲,居下,清虚,自然

将 mp3 以资源形式嵌入 exe 中使用 铜牌收录

本文讲解怎样将 mp3 等音乐资源以资源形式嵌入 exe 文件中,并通过 mciSendString 调用。嵌入 mp3 和嵌入图片略有不同,将图片嵌入到 exe 中,以及访问嵌入 exe 中的图片,请参考:https://codebus.cn/yangw/embed-pictures-in-an-exe-file

一、以资源文件形式嵌入 exe

关于“资源文件”的介绍和“将 mp3 以资源形式嵌入 exe 文件中”的步骤,请仿照 https://codebus.cn/yangw/embed-pictures-in-an-exe-file

二、播放资源文件中的 mp3

1. 思路

查看 MSDN 中关于 mciSendString 的使用,发现并不支持直接读取资源文件中的媒体文件,也不支持读取内存中的媒体文件。因此,我们需要提取资源

文件中的 mp3 为成临时文件,然后调用 mciSendString 播放,播放结束后再删掉这个临时文件。

2. 提取资源文件中的为临时文件

这个步骤不算复杂,只需要将资源文件中的资源读取到内存中,然后将内存数据写入文件即可。针对资源 ID 为字符串和宏两种形式,核心代码如下:

//////////////////////////////////////////////////////////////////
// 提取指定模块中的资源文件
// 参数:
//		strDstFile:		目标文件名。提取的资源将保存在这里;
//		strResType:		资源类型;
//		strResName:		资源名称;
// 返回值:
//		true: 执行成功;
//		false: 执行失败。
bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName)
{
	// 创建文件
	HANDLE hFile = ::CreateFile(strDstFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return false;

	// 查找资源文件、加载资源到内存、得到资源大小
	HRSRC	hRes	= ::FindResource(NULL, strResName, strResType);
	HGLOBAL	hMem	= ::LoadResource(NULL, hRes);
	DWORD	dwSize	= ::SizeofResource(NULL, hRes);
	
	// 写入文件
	DWORD dwWrite = 0;		// 写入大小
	::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL);
	::CloseHandle(hFile);

	return true;
}

3. 使用 mciSendString 播放音乐

这一步利用第 2 步导出的文件名,直接用 mciSendString 播放。mciSendString 的使用方法请参考:https://codebus.cn/yangw/play-music

4. 删除临时文件

临时文件如果不再使用,请及时删除。可以使用 windows api 函数 DeleteFile。

三、范例

范例 1

下面是一个完整的范例项目,该项目中有一个 "MP3" 类型的资源文件,资源 ID 为字符串 "background.mp3",播放这个 mp3 的范例代码如下:

///////////////////////////////////////////////////
// 程序名称:范例:播放以资源形式保存的 mp3 音乐
// 编译环境:Visual C++ 6.0 / 2010,EasyX 2011 惊蛰版
// 作  者:yangw80 <yw80@qq.com>
// 最后修改:2011-10-7
//
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#pragma comment(lib, "Winmm.lib")	// 引用 Windows Multimedia API
// #include "resource.h"			// 注:如果资源 ID 为宏定义,请取消这行注释


//////////////////////////////////////////////////////////////////
// 提取指定模块中的资源文件
// 参数:
//		strDstFile:		目标文件名。提取的资源将保存在这里;
//		strResType:		资源类型;
//		strResName:		资源名称;
// 返回值:
//		true: 执行成功;
//		false: 执行失败。
bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName)
{
	// 创建文件
	HANDLE hFile = ::CreateFile(strDstFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return false;

	// 查找资源文件、加载资源到内存、得到资源大小
	HRSRC	hRes	= ::FindResource(NULL, strResName, strResType);
	HGLOBAL	hMem	= ::LoadResource(NULL, hRes);
	DWORD	dwSize	= ::SizeofResource(NULL, hRes);
	
	// 写入文件
	DWORD dwWrite = 0;		// 返回写入字节
	::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL);
	::CloseHandle(hFile);

	return true;
}


// 主函数
int main()
{
	// 初始化图形窗口
	initgraph(640, 480);

	// 输出提示信息
	outtextxy(0, 0, _T("按任意键开始播放"));
	_getch();

	// 产生临时文件的文件名
	TCHAR tmpmp3[_MAX_PATH];
	::GetTempPath(_MAX_PATH, tmpmp3);
	_tcscat(tmpmp3, _T("testapp_background.mp3"));		// VC2008、VC2010 请用 _tcscat_s 函数

	// 将 MP3 资源提取为临时文件
	ExtractResource(tmpmp3, _T("MP3"), _T("background.mp3"));
	// 注:如果 MP3 资源的 ID 为宏 IDR_BACKGROUND,这样做:
	// ExtractResource(tmpmp3, _T("MP3"), MAKEINTRESOURCE(IDR_BACKGROUND));

	// 打开音乐
	TCHAR mcicmd[300];
	_stprintf(mcicmd, _T("open \"%s\" alias mymusic"), tmpmp3);		// VC2008、VC2010 请用 _stprintf_s 函数
	mciSendString(mcicmd, NULL, 0, NULL);

	// 播放音乐
	mciSendString(_T("play mymusic"), NULL, 0, NULL);

	// 输出提示信息
	outtextxy(0, 0, _T("按任意键停止播放"));
	_getch();

	// 停止播放并关闭音乐
	mciSendString(_T("stop mymusic"), NULL, 0, NULL);
	mciSendString(_T("close mymusic"), NULL, 0, NULL);

	// 删除临时文件
	DeleteFile(tmpmp3);

	// 输出提示信息
	outtextxy(0, 0, _T("按任意键退出程序"));
	_getch();

	// 关闭图形窗口
	closegraph();
	return 0;
}

范例 2 (完整)

范例 2 提供完整的播放嵌入音乐的功能,并内附项目文件、资源文件等,是完整的项目包,可以在 Visual C++ 6.0 下直接编译并执行。

<点击这里下载范例 2>

添加评论