从Exe里面读取资源,给exe增加嵌入字体

来源:互联网 发布:破解linux系统root密码 编辑:程序博客网 时间:2024/06/06 05:01

把数据放到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);
        }
    }
}

0 0
原创粉丝点击