您的位置:首页 > 其它

从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);

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: