给一下开源代码的路径http://code.ijinshan.com/trac/browser#bksafevul/publish,需要的同学可以完整下载,或者下bkres文件夹中的代码
资源处理的文件,一共9个,如下
bkbmppool.h
bkextraresdef.h
bkfontpool.h
bkjpgpool.h(这个目前没有)
bkpngpool.h
bkres.h
bkres.rc
bkresutil.h
bkstringpool.h
所谓“池”,即把资源统一放到某个地方,需要的时候取出,取出的逻辑有两种形式
a)懒汉式——即池中开始没资源,需要的时候才加载,一旦加载完,即成为缓存。以后只需读缓存,不需要再次加载
b)饿汉式——即初始化的时候,已经把所有资源投放到池里,第一次需要花费多些时间和存储空间,但是以后都只需要读缓存即可
一 总概
bkbmppool,bkfontpool,bkjpgpool,bkpngpool 四个资源池,使用的都是懒汉式,因为图片资源都比较大,需要的死后加载能减少内存。
bkstringpool则是饿汉式,原因很明显,文字内容毕竟是小空间的资源,一次加载完毕,可以加快速度。
bkextraresdef.h定义了扩展模块的接口,用做换肤,以后章节再详细说。
bkres.h文件包含了bkwinres.rc2和bkwinres.h,前者把资源打进本模块(比如dll),后者主要用来定义一些id宏,为了程序上能快速定位和统一使用资源id。
bkresutil.h封装了资源的加载顺序和方式
二 分析
1 字体资源池 bkfontpool.h
下面这段代码是实现“懒汉式”资源缓存的方式,很简单,通过一个static的CAtlMap<WORD, HFONT>类型m_mapFont存储
static HFONT GetFont(WORD uKey) {
// 查看资源池中有没制定字体 _TypeFontPool::CPair* pPairRet = _Instance()->m_mapFont.Lookup(uKey); HFONT hftRet = NULL; if (NULL == pPairRet) { hftRet = _Instance()->_CreateNewFont( BKF_ISBOLD(uKey), BKF_ISUNDERLINE(uKey), BKF_ISITALIC(uKey), BKF_GETADDING(uKey) ); if (hftRet) _Instance()->m_mapFont[uKey] = hftRet; } else hftRet = pPairRet->m_value; return hftRet; }
支持三种常用字体样式,分别是加粗、下划线和斜体
#define BKF_BOLD 0x0004U #define BKF_UNDERLINE 0x0002U #define BKF_ITALIC 0x0001U
2 图片资源池 bkbmppool,bkjpgpool,bkpngpool
这几个资源池的处理方法大同小异,处理方式和bkfontpool.h差不多
看到include头
#include <GdiPlus.h>
#pragma comment(lib, "gdiplus.lib")
就知道是通过Gdi+的方式来处理图片的,有一个地方需要注意的是
BkResManager::LoadResource(nID, strResource, BKRES_PNG_TYPE);
加载资源是通过bkresutil.h里面的LoadResource实现的,这个函数做了加载方式的封装,且看下文
3 资源应用类bkresutil.h
LoadResource函数使用两种方式加载资源,一种是从路径中加载,即当有外部路径,且资源名是id名时,直接加载资源文件。第二种是加载打进模块的资源,在bkwinres.rc2中定义的资源。只要两个地方有一个找到资源,就返回。_Instance()这个是单实例,返回static成员。
if (!_Instance()->m_strResourcePath.IsEmpty()) { CString strFileName; strFileName.Format(L"%s\\%d.bmp", _Instance()->m_strResourcePath, uResID); hBitmap = (HBITMAP)::LoadImage(NULL, strFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); if (NULL != hBitmap) return TRUE; } if (_Instance()->m_hInstanceRes) { hBitmap = ::LoadBitmap(_Instance()->m_hInstanceRes, MAKEINTRESOURCE(uResID)); if (NULL != hBitmap) return TRUE; }
路径和模块句柄设置入口
31 static void SetResourcePath(LPCTSTR lpszPath) 32 { 33 _Instance()->m_strResourcePath = lpszPath; 34 } 35 36 static void SetResourceDLL(LPCTSTR lpszPath) 37 { 38 if (_Instance()->m_hInstanceRes) 39 ::FreeLibrary(_Instance()->m_hInstanceRes); 40 41 _Instance()->m_hInstanceRes = ::LoadLibrary(lpszPath); 42 }
三 总结
感觉资源处理的文件很少,很简要。主要使用的技术是单实例,及资源池的概念,并不复杂。下一篇将介绍bkwin的内容,这个比bkres可要复杂很多