Symbian 上的资源文件问题

来源:互联网 发布:帝国cms还原数据 编辑:程序博客网 时间:2024/04/30 03:36

一、开始
不得不说,老汉是个不太安分的人,经常会做一些系统/平台不太推荐的事情。前一段时间在测试一个不使用 Symbian SDK 推荐的框架的最简化的 GUI 程序。在 EXE 里创建一个 RWindow 来显示内容并接收事件,我曾经在很久之前就写过,这次的需求略有不同,要能够在其中正常使用 CCoeControl 派生出来的控件(网上有一篇这方面的资料传播最为广泛:http://www.pushl.com/developers/exectrl.html。很不幸的是,其中有些只能用于 S60 第二版,例如涉及到的 CCoeAppUiSimple 这个类)。经过一些挫折后,总算是在模拟器里可以工作了,于是就想到真机上试试。

二、图标失效事件
要想让手机在应用程序中把程序显示出来,熟悉的开发人员都知道,需要有一个 xxx_reg.rss 资源文件。老汉在这里犯了一个很大的错误,过程是这样的。我的工程在最开始的时候,风格更接近于第二版的程序,几乎在所有的文件名种都没有 UID3 信息,中途为了更加符合三版的惯例,就修改了一次,把 UID3 加上了。最后把 SISX 部署到手机上之后发生了一个很奇怪的现象:在系统的九宫格里点击图标,不能启动程序,但是用调试器远程调试却又正常!这个问题困扰了我三四天,最终才发现竟然是忘记把 xxx_reg.rss 中 APP_REGISTRATION_INFO 结构里的 app_file 域中的可执行文件名相应地增加 UID3 而导致的。这个域很有意思,它必须与可执行文件的文件名匹配,但绝对不能写上扩展名!正是因为后面的这个限制,导致我在修改工程时误认为这个域仅仅是个描述性的文字,从而保留未动(没有附加上 UID3)!

三、显示名称事件
经过上面的修正,图标终于可以正常把我的程序启动起来了,不过另一件事情使得我的程序看起来很丑陋。图标下的文字是可执行文件名,而且毫不惊讶地,带着那个难看的 UID3!接下来的改进使我困惑:如果你想定制伴随图标显示的文字,正规的做法不是把这一信息也在 xxx_reg.rss 里指定,而是在 xxx.rss 资源文件里(一个 LOCALISABLE_APP_INFO 结构)!在 xxx_reg.rss 仅有一个链接性的信息,用 APP_REGISTRATION_INFO 结构中的两个域来描述,一个是 xxx.rss 编译后的资源文件名的 localisable_resource_file,一个是在该资源文件中包含了这一显示文字信息的结构的 ID 的 localisable_resource_id。难道我为了一个加起来不到 100 行代码的程序,竟然非要写两个 rss 文件出来?

经过仔细考察,我决定让 localisable_resource_file 指向 xxx_reg.rss 对应生成的资源文件自身。这下来了一个问题:正常的情况下,xxx.rss 在 xxx_reg.rss 之前被编译,会生成一个 rsg 文件,其中包含有 xxx.rss 中的所有资源结构所对应的 ID。这个 rsg 文件被 xxx_reg.rss 所引用,从而才可以给 localisable_resource_id 指定一个正确的值。但是现在不行了。如果我把 LOCALISABLE_APP_INFO 结构挪到 xxx_reg.rss 中来的话,那么我将无从知道资源编译器会把它的 ID 列为多少,也就无法给 localisable_resource_id 赋值。

当然,这样的困恼难不住老汉。我最终的做法是,先随便给 localisable_resource_id 写了一个数值,然后编译 xxx_reg.rss,然后找到它所生成的对应的 rsg 文件(也生成在 SDK 的 include 目录里),打开来看 LOCALISABLE_APP_INFO 的 ID 究竟成了几,然后把这个正确的数字更新到 localisable_resource_id 里,再次编译。这样就达到了一个资源文件即可满足系统所需信息的目的。

四、资源 ID 的戏法
在上面的过程中,有一件事情引起了我的注意。那些通常被我们定义时以 r_ 开头的名字命名的资源,与我们使用时所引用的对应的大写名称(其实是一个取值为数字的宏定义),究竟资源编译器是怎么生成对应关系的?

我对上面步骤所产生的 xxx_reg.rsg 文件进行了观察,看到 r_localisable_app_info(类型为 LOCALISABLE_APP_INFO)所对应的 ID(即 R_LOCALISABLE_APP_INFO)的值被定义为了 2。这不由得让我初步断定,这个值是根据 rss 文件中的 RESOURCE 定义顺序自增生成的,而且不管这个资源是否被命名了。在上例中,未命名的 APP_REGISTRATION_INFO 资源应该是占用了 1 这个 ID。带着这个结论去查看其他工程里的 rsg,得到了一个确认,一个疑惑。确认的是,ID 确实是按照前述顺序规则排列,疑惑是,这个顺序值仅占一个十六进制 DWORD 的后三位,前五位则各个 rsg 相异,不过在同一个 rsg 中总是相同的。这让我想起文档中提到的 rss 中 NAME 语句的定义不能冲突的问题,几乎可以认定这个前缀数值和 NAME 的定义值有关,但是一时找不到规律。

我写了一个批处理,来自动生成 NAME 名为 AAAA 到 AAAZ 的资源文件,并自动编译生成了对应的 rsg,可以看出前缀数值与名字一样,是一起增长的,然而准确规律依然未曾显现。不得已去 Symbian SDK 中搜索,找到了 ID 的顺序排列以及前缀数值由 NAME 变换而来的官方说法,不过并未提及变换算法。真正有价值的收获在于一个单词,offset,这是 SDK 文档中对我们前面的“前缀数值”的称谓。以此单词作为关键字到 google 上搜索,终于找到了答案,下面是经过我少些修改的变换算法代码,此工作至此告一段落。

long IdFromName(const char* name){/// REF: https://svn.symbianos.org/rcomp/trunk/src/rcomp.y// space 0// A1// B2// ...// Z26//// ABCD corresponds to the number 4321 which becomes ( (4*27 + 3) * 27 + 2) * 27 + 1.int length = 0;if(name)length = strlen(name);if(length > 4 || length <= 0)return -1;long new_id = 0;for(long i=0; i<length; i++){new_id *= 27;if(isalpha(name[i]))new_id += toupper(name[i]) - 'A' + 1;}long curr_id = new_id << 12;printf("Name=%s, Id offset=0x%08X(%d)/n", name, curr_id);return curr_id;}


为了日后便于追索,把上面提到的批处理的内容也列出来(symres.bat):

@echo offsetlocal ENABLEDELAYEDEXPANSIONif exist rcomp.exe goto beginecho rcomp.exe missed.goto quit:beginset uppercase=ABCDEFGHIJKLMNOPQRSTUVWXYZset lowercase=abcdefghijklmnopqrstuvwxyzset prefixu=AABset prefixl=aaBset counter=0:combineset suffixu=%uppercase:~0,1%set suffixl=%lowercase:~0,1%if "%suffixu%"=="" goto quitecho %suffixu%rem pauseset uppercase=%uppercase:~1%set lowercase=%lowercase:~1%rem Do our real work hereset stringu=%prefixu%%suffixu%set stringl=%prefixl%%suffixl%echo NAME %stringu% > r.rssecho STRUCT TBUF >> r.rssecho { >> r.rssecho LTEXT buf; >> r.rssecho } >> r.rssrem echo . >> r.rssecho RESOURCE TBUF %stringl% >> r.rssecho { >> r.rssecho buf = ""; >> r.rssecho } >> r.rssrcomp.exe -hr.rsg -sr.rsstype r.rsg >> list.rsgif not "%suffixu%"=="Z" goto combine:quitif exist r.rss del r.rssif exist r.rsg del r.rsg
原创粉丝点击