字符串资源格式浅谈

字符串资源格式浅谈

作者:BlogUpdater |  时间:2020-11-14 |  浏览:934 |  评论已关闭 条评论

字符串资源
在Win32图形化编程中,资源的ID定义在资源文件中并可以被代码引用。
其中,字符串资源和其他资源类型有点不一样,也即:字符串资源是打包在一起的。在知识库中有一篇文章Q196774对字符串的格式进行了简单的介绍,那么今天,我们就用实际的代码来更加深入地理解字符串资源的格式。

在资源文件列出的字符串以16个条目进行分组。所以,第一个字符串组合包含了第0个字符串到第15个字符串,第二个字符串组合包含了第16个字符串到第31个,以此类推。
如果从算法层面来描述,就是:第N个字符串组合包含了第(N – 1) * 16个字符串到第(N – 1) * 16 + 15个字符串。

在每一个字符串组合中的字符串使用UNICODE字符串来进行计数,而不是传统的空结束字符。如果计数之间存在间隔,则使用空字符串进行占位。所以,我们举个例子,如果你的字符串表只包含了第16个和第31个字符串,那么,这个字符串表中将会包含一个字符串组合(第2个字符串组合),其中包含第16个字符串,然后是14个空字符串,最后是第31个字符串。

请注意:根据上面的原理,我们没有办法分辨:第20个字符串是一个空字符串还是它根本不存在。

使用LoadString这个函数的时候,需要注意以下两个隐含限制:
> 不能向LoadString传递一个语言ID。如果你的资源是多语言的,则你将不能使用LoadString来加载一个非默认的语言字符串。
> 无法查询字符串资源中一个指定字符串的长度。

用实际的代码来理解
我们来看一下下面的例子,它可以用于去除上面所说的限制。

在上面的代码中,我们转换了字符串ID到一个组合数,这意味着我们找到了目标字符串所在的组合,然后我们加载这个资源组合并锁定。(我知道,这种访问资源的代码方式确实是个苦力活,实际上,早在Windows 3.1我们就开始使用这种方式来管理资源了,后面我会再详细讲讲这个主题)

接下来,我们开始对字符串表进行遍历,跳过了目标字符串直到我们找到我们想要的字符串。在每个字符串条目中,第一个WCHAR表示字符串的长度,所以我们跳过这个长度并以这个长度为单位跳过我们不感兴趣的字符串。

当我们完成遍历之后,pwsz指向了累加之后的字符串。

基于这个基础函数,我们可以创建一个更加简洁漂亮的版本。
下面的FindStringResource函数时一个简单的封装,它可以以线程默认语言来对字符串表进行搜索目标字符串。

我们也编写了一个函数GetResourceStringLengthEx来返回目标字符串的长度,包含结尾的空字符。

接下里,AllocStringFromResourceEx这个帮助函数可以加载指定字符串到基于堆的内存区。

(上面的GetStringResourceLength和AllocStringFromResource都带有Ex,大家可以试试自己编写不带Ex的版本)

请注意,我们必须手动对字符串添加结尾的空字符,因为字符串资源表中的字符串是不带这个空字符的。还要注意的是,不要忘记释放AllocStringFromResourceEx返回的字符串,因为它是分配在堆上,如下图所示:

注意上面的释放使用的是delete[],而不是delete,我将在后面的文章中详细讲讲这个区别以及可能导致的问题,请拭目以待。

练习题
请研究下rc.exe中的/n选项时如何影响这些函数的行为的。

总结
十几年过去了,我特意打开我的Visual Studio工程,找到RC文件:Raymond确实没有骗我,字符串确实如他所说,是以16为单位进行组合分组的。
我突然就感觉到了:有些事,它一直没有变。

最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《The format of string resources》

标签:

评论已关闭。