添加和提取二进制资源






4.90/5 (46投票s)
2003 年 5 月 29 日
4分钟阅读

217389

9458
初学者指南,介绍如何在 Visual Studio 中添加二进制资源,以及一个用于编程提取的简单类。
引言
有时您可能希望在应用程序中包含二进制资源,并在以后动态提取它们。如何使用 BinRes 类
使用BinRes
类非常简单。请按照以下步骤将其用于现有项目。将源文件 (BinRes.cpp
和 BinRes.h
) 放入您希望使用它们所在的目录后,将这些文件添加到您的 Visual Studio 项目中。在您要使用该类的文件中包含 binres.h
。
#include "binres.h"
无需创建 BinRes
的实例,因为所有成员函数都声明为静态。您可以选择使用 setOutputPath
设置一个输出路径,用于写入二进制文件。
BinRes::setOutputPath(strPath);
最后,调用 ExtractBinResource
,传入资源名称、资源标识符和您希望为二进制文件指定的输出名称。例如:
CTestHarnessDlg::OnExtractResource()
{
BinRes::ExtractBinResource("BIN", 132, "debugViewer.exe");
}
完成以上步骤,您就可以利用 BinRes
类了。
设置您的二进制资源
要在我们的应用程序中使用 BinRes
类,首先需要添加一个二进制文件。对于我包含的二进制文件,我决定访问 www.sysinternals.com 并下载非常出色的 DebugView
应用程序(它允许您监视本地系统上的 OutputDebugString
调用)。这个可执行文件是我们将在资源中使用的。
好的,在 Visual Studio 中选择 ResourceView
选项卡,右键单击资源,然后选择“导入”以导入新资源。
在“导入资源”对话框中,从“打开方式”组合框中选择“自定义”,从“文件类型”组合框中选择“所有文件 (*.*)”,然后导航到您要添加到资源中的二进制文件。我已经选择了 Dbgview.exe
。
在“自定义资源类型”对话框中,输入一个合适的名称。我选择了“BIN”,它是“BINARIES”的缩写。
就这样。我们已成功将二进制资源添加到我们的测试应用程序资源中。现在让我们继续研究如何使用代码。
检查代码
与 BinRes
类一起使用的主要函数是 ExtractBinResource
。现在让我们来详细分析这个类函数,看看具体发生了什么。下面是该函数的完整代码。
void BinRes::ExtractBinResource(std::string strCustomResName,
int nResourceId,
std::string strOutputName)
{
HGLOBAL hResourceLoaded; // handle to loaded resource
HRSRC hRes // handle/ptr to res. info.
char *lpResLock // pointer to resource data
DWORD dwSizeRes;
std::string strOutputLocation;
std::string strAppLocation;
// lets get the app location
strAppLocation = getAppLocation();
strOutputLocation = strAppLocation += "\\";
strOutputLocation += strOutputName;
hRes = FindResource(NULL,
MAKEINTRESOURCE(nResourceId),
strCustomResName.c_str()
);
hResourceLoaded = LoadResource(NULL, hRes);
lpResLock = (char *) LockResource(hResourceLoaded);
dwSizeRes = SizeofResource(NULL, hRes);
std::ofstream outputFile(strOutputLocation.c_str(), std::ios::binary);
outputFile.write((const char *) lpResLock, dwSizeRes);
outputFile.close();
}
在设置完变量后,调用的第一个 API 是 FindResource
。它根据 nResourceId
查找资源的位置并获取其句柄。显然,我们需要这个句柄才能加载资源。
hRes = FindResource(NULL,
MAKEINTRESOURCE(nResourceId),
strCustomResName.c_str()
);
下一行将我们的资源加载到内存中,以便我们可以处理它。
hResLoad = LoadResource(NULL, hRes);
一旦我们的资源加载完成,我们就会获得指向它的指针,以便我们可以遍历数据并将其写入输出文件。我们通过调用 LockResource
来获取指针。
lpResLock = (char *) LockResource(hResLoad);
现在我们有了指向内存中资源的指针,但是资源有多大呢?我们怎么知道何时停止将数据写入输出文件?理想情况下,我们需要获取资源的大小,我们通过调用恰如其分的 API SizeofResource
来做到这一点。
dwSizeRes = SizeofResource(NULL, hRes);
现在我们已经拥有了将数据写入文件的所有必需信息。我们拥有输出名称(由调用者传入)、指向内存中资源的指针以及资源的大小,所以接下来我们做的就是为文件打开一个输出流。
std::ofstream outputFile(strTemp.c_str(), std::ios::binary);
在打开输出文件后,我们使用 ofstream 的 write
方法将内存中的资源数据写入打开的文件。
outputFile.write((const char *) lpResLock, dwSizeRes);
最后一步是关闭文件。
outputFile.close();
ExtractBinResource 参数说明
- 第一个参数是我们添加二进制资源到项目时创建的新资源类型的名称。在本例中,我们将新类型命名为“BIN”,并以此作为传入参数。
- 第二个参数是我们二进制资源的资源 ID。在
ResourceView
选项卡中,它显示为IDR_BIN1
,但如果您打开resource.h
,您会发现IDR_BIN1
是一个数字的别名。这就是我们需要作为第二个参数传入的数字。 - 第三个参数是首选的二进制文件的输出名称。很简单!
BinRes::ExtractBinResource("BIN", 132, "debugViewer.exe");
结论
就这样!大功告成。我的第一篇 CP 文章完成了。该类可能的改进包括添加一个输出位置。目前,文件会输出到程序运行的同一目录。当然,我们欢迎所有的建议/反馈/错误报告。
历史
- 版本 1 - 2003 年 5 月 21 日 - 初版