首页 > 代码库 > 第十一篇:SOUI系统资源管理
第十一篇:SOUI系统资源管理
从前篇已经讲到在SOUI中所有资源文件通过一个uires.idx文件进行索引。
这里将介绍在程序中如何引用这些资源文件。
在SOUI系统中,资源文件通过一个统一的接口对象读取:
namespace SOUI{ enum BUILTIN_RESTYPE { RES_PE=0, RES_FILE, }; /** * @struct IResProvider * @brief ResProvider对象 * * Describe 实现各种资源的加载 */ struct IResProvider : public IObjRef { /** * Init * @brief 资源初始化函数 * @param WPARAM wParam -- param 1 * @param LPARAM lParam -- param 2 * @return BOOL -- true:succeed * * Describe every Resprovider must implement this interface. */ virtual BOOL Init(WPARAM wParam,LPARAM lParam) =0; /** * HasResource * @brief 查询一个资源是否存在 * @param LPCTSTR strType -- 资源类型 * @param LPCTSTR pszResName -- 资源名称 * @return BOOL -- true存在,false不存在 * Describe */ virtual BOOL HasResource(LPCTSTR strType,LPCTSTR pszResName)=0; /** * LoadIcon * @brief 从资源中加载ICON * @param LPCTSTR pszResName -- ICON名称 * @param int cx -- ICON宽度 * @param int cy -- ICON高度 * @return HICON -- 成功返回ICON的句柄,失败返回0 * Describe */ virtual HICON LoadIcon(LPCTSTR pszResName,int cx=0,int cy=0)=0; /** * LoadBitmap * @brief 从资源中加载HBITMAP * @param LPCTSTR pszResName -- BITMAP名称 * @return HBITMAP -- 成功返回BITMAP的句柄,失败返回0 * Describe */ virtual HBITMAP LoadBitmap(LPCTSTR pszResName)=0; /** * LoadCursor * @brief 从资源中加载光标 * @param LPCTSTR pszResName -- 光标名 * @return HCURSOR -- 成功返回光标的句柄,失败返回0 * Describe 支持动画光标 */ virtual HCURSOR LoadCursor(LPCTSTR pszResName)=0; /** * LoadImage * @brief 从资源加载一个IBitmap对象 * @param LPCTSTR strType -- 图片类型 * @param LPCTSTR pszResName -- 图片名 * @return IBitmap * -- 成功返回一个IBitmap对象,失败返回0 * Describe 如果没有定义strType,则根据name使用FindImageType自动查找匹配的类型 */ virtual IBitmap * LoadImage(LPCTSTR strType,LPCTSTR pszResName)=0; /** * LoadImgX * @brief 从资源中创建一个IImgX对象 * @param LPCTSTR strType -- 图片类型 * @param LPCTSTR pszResName -- 图片名 * @return IImgX * -- 成功返回一个IImgX对象,失败返回0 * Describe */ virtual IImgX * LoadImgX(LPCTSTR strType,LPCTSTR pszResName)=0; /** * GetRawBufferSize * @brief 获得资源数据大小 * @param LPCTSTR strType -- 资源类型 * @param LPCTSTR pszResName -- 资源名 * @return size_t -- 资源大小(byte),失败返回0 * Describe */ virtual size_t GetRawBufferSize(LPCTSTR strType,LPCTSTR pszResName)=0; /** * GetRawBuffer * @brief 获得资源内存块 * @param LPCTSTR strType -- 资源类型 * @param LPCTSTR pszResName -- 资源名 * @param LPVOID pBuf -- 输出内存块 * @param size_t size -- 内存大小 * @return BOOL -- true成功 * Describe 应该先用GetRawBufferSize查询资源大小再分配足够空间 */ virtual BOOL GetRawBuffer(LPCTSTR strType,LPCTSTR pszResName,LPVOID pBuf,size_t size)=0; /** * FindImageType * @brief 查询与指定名称匹配的资源类型 * @param LPCTSTR pszImgName -- 资源名称 * @return LPCTSTR -- 资源类型,失败返回NULL * Describe 没有指定图片类型时默认从这些类别中查找 */ virtual LPCTSTR FindImageType(LPCTSTR pszImgName) =0; }; /** * Helper_FindImageType * @brief 查询与指定名称匹配的资源类型 * @param IResProvider * pResProvider -- 当前的ResProvider * @param LPCTSTR pszImgName -- 资源名称 * @return LPCTSTR -- 资源类型,失败返回NULL * Describe 提供一个公共的辅助函数 */ }//namespace SOUI
这个接口的实现类通过实现这些既定接口来完成图标(HICON),光标(HCURSOR),位图(HBITMAP),一般图片(IBitmap)的解码,同时也提供原始数据(RawData)的读取。
在SOUI系统中内置了两种类型的资源加载(ResProvider)模块:SResProviderPE 和 SResProviderFiles,同时也通过外置组件的形式提供了从ZIP文件加载资源的功能。
这三种资源加载方式基本上涵盖了目前常见的资源加载方式。
为了能够从PE的资源数据段中加载资源,我们需要将uires.idx中索引的文件转换成PE资源可以识别的资源类型+资源名(不是资源ID)的形式。
为了达到这个目的,我们只需要在VS的资源文件中(.rc)将SOUI的资源中定义的文件按照uires.idx定义的类型和名称加进去即可。
手工添加资源文件很难保证不写错。为此,我提供了一个工具(tools\uiresbuilder.exe),这个工具接收一组命令参数,用来将uires.idx转换成一个RC编译器可以识别的.rc2文件(命令行参见使用向导生成的工程)。要编译该.rc2文件,需要在.rc的资源包含中加上我们生成的.rc2文件。
如果程序中的资源不从PE资源加载,则不需要编译soui_res.rc2文件,以减少程序体积。
SResProviderPE, SResProviderFiles 和 SResProviderZIP分别从PE资源,文件夹及ZIP文件包中初始化资源:
#if (RES_TYPE == 0)//从文件加载 CreateResProvider(RES_FILE,(IObjRef**)&pResProvider); if(!pResProvider->Init((LPARAM)_T("uires"),0)) { SASSERT(0); return 1; }#elif (RES_TYPE==1)//从EXE资源加载 CreateResProvider(RES_PE,(IObjRef**)&pResProvider); pResProvider->Init((WPARAM)hInstance,0);#elif (RES_TYPE==2)//从ZIP包加载 bLoaded=pComMgr->CreateResProvider_ZIP((IObjRef**)&pResProvider); SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("resprovider_zip")); ZIPRES_PARAM param; param.ZipFile(pRenderFactory, _T("uires.zip"),"souizip"); bLoaded = pResProvider->Init((WPARAM)¶m,0); SASSERT(bLoaded);#endif
资源加载成功后,调用SApplication::AddResProvider(IResProvider *)接口将创建的资源加载器交给SOUI系统管理。
SApplication::AddResProvider可以调用多次,便于加载不同的资源。
资源加载后不再需要了也可以使用SApplication::RemoveResProvider(IResProvider *)来删除。
程序中要使用一个资源时,首先调用SApplication::HasResource来查询一个资源是否存在,然后再根据资源类型选择不同的接口加载资源。
SApplication中管理着一个IResProvider列表,系统采用后进先查的算法处理资源重名,即最后调用AddResProvider加进来的资源加载器优先级最高。
第十一篇:SOUI系统资源管理