首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

2013-03-16 
以金山界面库(openkui)为例思考和分析界面库的设计和实现——资源读取模块分析按照软件的执行流程,我们首先

以金山界面库(openkui)为例思考和分析界面库的设计和实现——资源读取模块分析

        按照软件的执行流程,我们首先遇到《以金山界面库(openkui)为例思考和分析界面库的设计和实现——问题》中提出的最后一个问题:界面描述文件的放置位置。我们曾提出一种方案:将界面描述文件打包后放在资源文件中;在使用时,解析并读取资源文件。实际上Kui也是按照我们这个思路在做的,只是做得比我们要精巧。在阅读这部分代码的过程中,我发现其存在一定的编码缺陷以及设计缺陷。我会在文中适时指出问题并提出修正及改进的方案。(转载请指明出于breaksoftware的csdn博客)

        为了表述方便,我们将以KUI自带的例子工程Sample1为例。在该项目的res目录下,我们看到一个名字为sample1.kui的文件。

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

        在Sample1工程的资源文件中,上图中sample1.kui将作为一个类型为“SKIN”,名字为“KUIRED.DAT”的资源。

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

        从这个特殊的后缀名.kui可以猜测出,这个文件是一个压缩文件。

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

        这样,我们心里有了底,同时为我们阅读Kui的资源管理代码提供了视觉上的参考。
        在openkui\KUILib\kscbase\src下有个文件kscres.cpp。它定义了资源文件处理逻辑。
        首先,我们查看这段代码


        除了“读取String”、“读取Image”和“读取字体”资源外,我们可能比较难以猜测到其他过程做了什么。如果按照我前一篇的思路,“预处理资源文件”可能对应于“读取指定资源”,“打开资源文件”可能对应于“将压缩包文件解压”,是不是如此呢?我们拭目以待。在解读之后的代码之前,我有个疑问,这些操作如果有一步没有成功,还有必要继续往下走么?怎么就没一个判断?放下这个问题,我们看之后的代码。

        我们先看


        这个流程,我们可以看出来,其大体思路和我之前猜测的一致,只是它增加了优先对独立的压缩包资源文件的处理。于是我们可以得出:Kui的界面描述文件,可以放在:
        1 Exe文件所在的目录下,名字和Exe相同的、后缀为kui的文件(以后简称界面文件包)中
        2 PE文件资源类型为“SKIN”、名字为“kuires.dat”的资源(以后简称界面内存块)中
        其中1的优先级要高于2。
        这种设计方案还是很有意思的。因为这个流程可以实现换肤功能。比如我们下载了A.kui、B.kui、C.kui和D.kui四套皮肤。如果用户选择了A皮肤,则我们可以将A.kui拷贝到Exe所在目录,并将其命名为与Exe同名、后缀为kui的名字。这样就实现了换肤。即使这套外置皮肤坏了,或者被删了,我们还可以使用资源中的那套皮肤。

        虽然想法很好,但是代码中的逻辑却存在一定的编码缺陷和设计缺陷,我们先说编码缺陷:


        如此,便将压缩包中的文件信息保存到Map结构体对象m_mapResOffset中。其中信息包括文件的相对目录,文件的相对偏移和大小。
        有了这组信息,我们之后读取单个文件,将变得非常方便了。
        以上我们讨论了如何使用Zlib获取界面压缩包中文件信息的方法。现在我们再看下如何使用Zlib从界面内存块中获取压缩后的文件信息。

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

        是否还记得,之前我着重提到一点“使用了fill_win32_filefunc填充了zlib_filefunc_def结构体”。之所以着重,是因为我们现在解析界面内存块的信息时,将要自己填充zlib_filefunc_def结构体中各个回调函数。我们先看fill_win32_filefunc内部的实现


        KUI提供的例子中,都没有LoadFontRes对应的fonts.xml文件存在。所以我们可以先忽略字体处理这块逻辑。
        我们以LoadXmlRes为例,讲解其执行过程。


        我们看一下xmls.xml文件内容


        在使用KUI库的程序中,我们将使用到这些id。
        我们看下最终的读取结果

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

以金山界面库(openkui)替例思考和分析界面库的设计和实现——资源读取模块分析

        我们注意到res目录下三个文件这个时候并没有加载。为什么不加载,我们之后会在探索《以金山界面库(openkui)为例思考和分析界面库的设计和实现——问题》中“如何读取保存界面元素属性”问题时,对这个问题作出解释。
        总体来说,KUI这套资源管理逻辑存在以下问题:
        1 部分代码不严谨
        2 设计缺乏对debug环境下的优化
        3 读取资源代码容余,应该封装下

bool KAppRes::GetResInResfile(){    bool retval = false;    HRSRC hResInfo = NULL;    HGLOBAL hResDat = NULL;    PVOID pResBuffer = NULL;    DWORD dwResBuffer;    hResInfo = FindResourceW(_ModulePtr->GetResourceInstance(), L"kuires.dat", L"SKIN");    if (!hResInfo)        goto clean0;    hResDat = LoadResource(_ModulePtr->GetResourceInstance(), hResInfo);    if (!hResDat)        goto clean0;    pResBuffer = LockResource(hResDat);    if (!pResBuffer)        goto clean0;    dwResBuffer = SizeofResource(_ModulePtr->GetResourceInstance(), hResInfo);    m_memZipRes.SetData(pResBuffer, dwResBuffer);    retval = true;clean0:    return retval;}
        也有其出彩的地方:
        1 CMemFile类的编写
        2 从内存中解压文件

热点排行