从Exe里面读取资源,给exe增加嵌入字体
2014-05-09 15:53
239 查看
把数据放到Exe文件里面有很多好处,理由也很多,比如:
隐藏数据,不想让用户看见。
数据太零散,小文件太多。
减少体积,提高加载速度等。
等等。这方面的例子也很多,就不细说了。我这里只说说将一类资源全部打包到一个压缩文件中,然后程序中读取的方法。
一个zip压缩包中,包含了大量的文件,并且还有多级目录,我们可以将整个资源全部提取出来,存入到一个内存文件(buffer)中。
从资源中提取数据到内存的方法很简单,代码如下:
bool LoadResToMemFile(unsigned int resid, const std::wstring res_type, MemFile* memfile)
{
bool ret = false;
HRSRC hResInfo = FindResource(m_hResource, MAKEINTRESOURCE(resid), res_type.c_str());
if (hResInfo)
{
HGLOBAL hResDat = LoadResource(m_hResource, hResInfo);
if (hResDat)
{
PVOID pResBuffer = LockResource(hResDat);
if (pResBuffer)
{
DWORD dwResBuffer = SizeofResource(m_hResource, hResInfo);
memfile->SetData(pResBuffer, dwResBuffer);
ret = true;
}
}
}
return ret;
}
在整个资源文件提取出来之后,需要将里面的每个文件都解析出来,并保存到一个映射表中,只有这样,才能保证在给出文件名称后,快速定位到该文件的内存。
这时需要定义好一个数据类型:
typedef std::pair<unsigned long, unsigned long> KResInfo;
typedef std::map<std::wstring, KResInfo> KResOffset;
KResInfo中的两个值,分别为偏移位置和文件长度。如果使用zip压缩的资源,使用下面的代码快速创建映射表:
m_pResPackData = unzOpen2((const char*)&m_memZipRes, &zip_funcs);
nRetCode = unzGoToFirstFile(m_pResPackData);
while (UNZ_OK == nRetCode)
{
char szCurrentFile[260];
unz_file_info fileInfo;
uLong dwSeekPos;
uLong dwSize;
nRetCode = unzGetCurrentFileInfo(
m_pResPackData,
&fileInfo,
szCurrentFile,
sizeof(szCurrentFile),
NULL,
0,
NULL,
0
);
if (nRetCode != UNZ_OK)
goto clean0;
dwSeekPos = unzGetOffset(m_pResPackData);
dwSize = fileInfo.uncompressed_size;
std::wstring filename = AnsiToUnicode(szCurrentFile, -1);
FormatFilePath(filename);
m_mapResOffset.insert(KResOffset::value_type(filename, KResInfo(dwSeekPos, dwSize)));
nRetCode = unzGoToNextFile(m_pResPackData);
}
unzClose(m_pResPackData);
映射表创建好之后,就可以快速的从里面取出一段文件的buffer内容了:
bool GetDataFromRes(
const std::wstring& filepath,
void** ppBuffer,
unsigned long& dwSize
)
{
bool retval = false;
KResOffset::iterator offset;
unsigned long dwOffset;
int nRetCode;
if (!ppBuffer)
return false;
std::wstring filename = filepath;
FormatFilePath(filename);
offset = m_mapResOffset.find(filename);
if (offset == m_mapResOffset.end())
return false;
dwOffset = offset->second.first;
dwSize = offset->second.second;
*ppBuffer = new unsigned char[dwSize + 4];
if (!*ppBuffer)
return false;
memset(*ppBuffer, 0, dwSize + 4);
nRetCode = unzSetOffset(m_pResPackData, dwOffset);
if (nRetCode == UNZ_OK)
{
nRetCode = unzOpenCurrentFile(m_pResPackData);
if (nRetCode == UNZ_OK)
{
nRetCode = unzReadCurrentFile(m_pResPackData, *ppBuffer, dwSize);
if (0 != nRetCode)
retval = true;
}
}
if (!retval)
{
if (ppBuffer)
{
if (*ppBuffer)
{
delete[] (*ppBuffer);
*ppBuffer = NULL;
}
}
}
return retval;
}
这个里面要注意的是,内存需要由外部释放。对于zip压缩程序来说,它里面使用的文件名全部是“/”,而windows里面文件名为“\”,因此需要做转换,这个转换函数就是:
void FormatFilePath(std::wstring & filepath)
{
int len = filepath.length();
for(int i=0; i<len; i++)
{
if (filepath[i] == L'/')
filepath[i] = L'\\';
}
}
好了,以上的代码就可以完成内嵌文件的释放,比如我们要完成一个内嵌字体,增加以下代码就可以了:
void LoadFontFile(const std::wstring & file)
{
std::wstring fullName = GetResourceRootPath() + L"/" + file;
if (GetFileAttributes(fullName.c_str()) != INVALID_FILE_ATTRIBUTES)
{
AddFontResourceExW(fullName.c_str(), FR_PRIVATE, 0);
}
else
{
void * buf = NULL;
unsigned long bufSize = 0;
if (GetRawDataFromRes(file, &buf, bufSize))
{
DWORD dw = 0;
HANDLE hFont = AddFontMemResourceEx(buf, bufSize, 0, &dw);
FreeRawData(buf);
}
}
}
隐藏数据,不想让用户看见。
数据太零散,小文件太多。
减少体积,提高加载速度等。
等等。这方面的例子也很多,就不细说了。我这里只说说将一类资源全部打包到一个压缩文件中,然后程序中读取的方法。
一个zip压缩包中,包含了大量的文件,并且还有多级目录,我们可以将整个资源全部提取出来,存入到一个内存文件(buffer)中。
从资源中提取数据到内存的方法很简单,代码如下:
bool LoadResToMemFile(unsigned int resid, const std::wstring res_type, MemFile* memfile)
{
bool ret = false;
HRSRC hResInfo = FindResource(m_hResource, MAKEINTRESOURCE(resid), res_type.c_str());
if (hResInfo)
{
HGLOBAL hResDat = LoadResource(m_hResource, hResInfo);
if (hResDat)
{
PVOID pResBuffer = LockResource(hResDat);
if (pResBuffer)
{
DWORD dwResBuffer = SizeofResource(m_hResource, hResInfo);
memfile->SetData(pResBuffer, dwResBuffer);
ret = true;
}
}
}
return ret;
}
在整个资源文件提取出来之后,需要将里面的每个文件都解析出来,并保存到一个映射表中,只有这样,才能保证在给出文件名称后,快速定位到该文件的内存。
这时需要定义好一个数据类型:
typedef std::pair<unsigned long, unsigned long> KResInfo;
typedef std::map<std::wstring, KResInfo> KResOffset;
KResInfo中的两个值,分别为偏移位置和文件长度。如果使用zip压缩的资源,使用下面的代码快速创建映射表:
m_pResPackData = unzOpen2((const char*)&m_memZipRes, &zip_funcs);
nRetCode = unzGoToFirstFile(m_pResPackData);
while (UNZ_OK == nRetCode)
{
char szCurrentFile[260];
unz_file_info fileInfo;
uLong dwSeekPos;
uLong dwSize;
nRetCode = unzGetCurrentFileInfo(
m_pResPackData,
&fileInfo,
szCurrentFile,
sizeof(szCurrentFile),
NULL,
0,
NULL,
0
);
if (nRetCode != UNZ_OK)
goto clean0;
dwSeekPos = unzGetOffset(m_pResPackData);
dwSize = fileInfo.uncompressed_size;
std::wstring filename = AnsiToUnicode(szCurrentFile, -1);
FormatFilePath(filename);
m_mapResOffset.insert(KResOffset::value_type(filename, KResInfo(dwSeekPos, dwSize)));
nRetCode = unzGoToNextFile(m_pResPackData);
}
unzClose(m_pResPackData);
映射表创建好之后,就可以快速的从里面取出一段文件的buffer内容了:
bool GetDataFromRes(
const std::wstring& filepath,
void** ppBuffer,
unsigned long& dwSize
)
{
bool retval = false;
KResOffset::iterator offset;
unsigned long dwOffset;
int nRetCode;
if (!ppBuffer)
return false;
std::wstring filename = filepath;
FormatFilePath(filename);
offset = m_mapResOffset.find(filename);
if (offset == m_mapResOffset.end())
return false;
dwOffset = offset->second.first;
dwSize = offset->second.second;
*ppBuffer = new unsigned char[dwSize + 4];
if (!*ppBuffer)
return false;
memset(*ppBuffer, 0, dwSize + 4);
nRetCode = unzSetOffset(m_pResPackData, dwOffset);
if (nRetCode == UNZ_OK)
{
nRetCode = unzOpenCurrentFile(m_pResPackData);
if (nRetCode == UNZ_OK)
{
nRetCode = unzReadCurrentFile(m_pResPackData, *ppBuffer, dwSize);
if (0 != nRetCode)
retval = true;
}
}
if (!retval)
{
if (ppBuffer)
{
if (*ppBuffer)
{
delete[] (*ppBuffer);
*ppBuffer = NULL;
}
}
}
return retval;
}
这个里面要注意的是,内存需要由外部释放。对于zip压缩程序来说,它里面使用的文件名全部是“/”,而windows里面文件名为“\”,因此需要做转换,这个转换函数就是:
void FormatFilePath(std::wstring & filepath)
{
int len = filepath.length();
for(int i=0; i<len; i++)
{
if (filepath[i] == L'/')
filepath[i] = L'\\';
}
}
好了,以上的代码就可以完成内嵌文件的释放,比如我们要完成一个内嵌字体,增加以下代码就可以了:
void LoadFontFile(const std::wstring & file)
{
std::wstring fullName = GetResourceRootPath() + L"/" + file;
if (GetFileAttributes(fullName.c_str()) != INVALID_FILE_ATTRIBUTES)
{
AddFontResourceExW(fullName.c_str(), FR_PRIVATE, 0);
}
else
{
void * buf = NULL;
unsigned long bufSize = 0;
if (GetRawDataFromRes(file, &buf, bufSize))
{
DWORD dw = 0;
HANDLE hFont = AddFontMemResourceEx(buf, bufSize, 0, &dw);
FreeRawData(buf);
}
}
}
相关文章推荐
- 将C#程序嵌入资源中(C# 调用嵌入资源的EXE文件方法)
- 读取嵌入的资源文件
- 读取嵌入到 Dll 文件中的资源文件
- 将.xsd文件嵌入资源 读取嵌入文件 并 读入到DataSet架构
- java 读取资源文件并且动态设置资源里面的参数demo
- winfrom中,嵌入的资源文件路径,并读取txt文件
- 关于使用GetManifestResourceStream读取嵌入资源为null的问题
- winform 嵌入资源读取使用
- 读取嵌入到 Dll 文件中的资源文件
- [转]将字体嵌入程序资源中 C# Winform
- 介绍一个可以读取保存在程序集里面的图片资源的小工具
- 在.NET中读取嵌入和使用资源文件的方法
- 嵌入资源的方式让Winform使用系统没有的字体,无需安装字体
- 在.NET中读取嵌入和使用资源文件的方法
- [C++] 将 mp3 等音乐资源以资源形式嵌入 exe 文件中
- WPF在资源内嵌入字体
- dotNet读取嵌入资源的办法。
- 在.NET中读取嵌入和使用资源文件的方法
- 获取exe和dll里面的资源
- 黄聪:将C#程序嵌入资源中(C# 调用嵌入资源的EXE文件方法)