TONT 42973 Windows 95 中关于DLL资源文件的限制

为了与旧世界协调相连,我们做了一些妥协。

原文链接:https://blogs.msdn.microsoft.com/oldnewthing/20030807-00/?p=42973

Ancient history lesson.

今天我们来讲讲古代历史。

When Win9x loads a 32-bit DLL, it creates a shadow 16-bit DLL so 16-bit code (like USER) can access resources in it.

当Windows 9x加载32位DLL时,系统会创建一个它的16位镜像,以便16位的应用(如USER)可以存取其中的资源文件。

The shadow DLL is effectively a resource-only 16-bit DLL, created by taking the 32-bit resources and converting them to 16-bit format. If the resources cannot be converted to 16-bit format, the DLL will not load.

这个镜像大体等同于一个只有资源文件的16位DLL,通过将32位资源进行提取、并转换为16位资源而成。如果资源无法转换为16位格式,那么这个DLL就无法被加载。

The 16-bit resource file format specifies resource sizes by combining a DLL-wide shift value with a 16-bit per-resource scaled size. So, for example, if the shift value were 2, and the per-resource scaled size were 8, then the actual resource size would be 8 << 2 = 32.

16位DLL中的资源文件,通过将一个相对于当前DLL为全局的偏移量和一个应用于各16位资源的尺寸乘数进行组合,来确定该资源的尺寸。例如,如果偏移量为2,各资源尺寸乘数为8,那么实际的资源尺寸就是8<<2=32。

Windows 95 has a bug in the way it calculates the scaled size.

对于Windows 95而言,计算这个乘数时有一个bug。

If the Windows 95 kernel decided that it needed to use a nonzero shift value because the 32-bit DLL contains a resource larger than 64K, it scaled the 32-bit values down to 16-bit values and rounded down rather than up. So, for example, if a resources were 65537 bytes in size and the shift factor were 1, then the scaled-down value would be 65537 >> 1 = 32768. After scaling back up, the result would be 32768 >> 1 = 65536. Notice that the value is too small; the last byte of the resource has been truncated.

如果Windows 95的内核认为,由于某32位DLL的资源尺寸大于64K,所以应当使用一个非0的偏移量对资源尺寸进行计算时,会将32位值(译注:32位整数的无符号最大值为2147483647)按比例缩小为一个16位值(译注:无符号最大值32767),并进行向下取整(译注:3.5向下取整=3)而不是四舍五入(译注:3.5四舍五入=4)。因此,举个例子来说,如果某资源尺寸为65537字节,偏移量为1,那么等比缩小的值将为65537>>1=32768,等比放大时将变成32768>>1=65536。请注意这个值是很小的,且资源的最后一个字节还被砍掉了。

Consequently, if you have a 32-bit DLL with resources 64K or larger, you must pad those resources to prevent this truncation from happening. In the above example, you would have to pad the resource to 65538 bytes, so that the scaled-down value would be 32769, which scales back up to 65538.

因此,如果你的32位DLL中包含64K及以上大小的资源,必须将资源数据按照64K边界进行对齐,以免上述的截断事项发生。在上面的例子中,资源文件应补齐至65538字节,这样运算时等比缩小为16位值时尺寸为32769字节,放大后才是正确的65538。

I believe this bug was fixed in Windows 98 but I’m not sure. There is a little program in the SDK called fixres95 that generates the necessary padding.

我觉得这个bug在Windows 98里应该已经修复了,不过不怎么确定。SDK中有个叫fixres95的小程序可以帮助处理这个问题。

Other limitations of the 16-bit resource file format you may run into:

另外还有一些在处理16位资源文件时可能遇到的问题:

  • Ordinal resource identifiers may not exceed 32767.
  • 资源文件的序数不能超过32767。
  • The total lengths of named resources may not exceed 65535 (where each name counts one byte for each character in the name, plus one). Named resources have been a bad idea since Windows 1.0. They are a convenience that you can easily live without most of the time, and they are significantly more costly, as you can see.
  • 对资源命名的总长度不能超过65535(每个字符算一个字节,然后再+1)。其实从Windows 1.0开始,命名资源文件就不是个好主意,它的好处基本上体会不到,但带来的坏处却是显而易见的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

 剩余字数 ( Characters available )

Your comment will be available after auditing.
您的评论将在通过审核后显示。

Please DO NOT add any links in your comment, otherwise it would be identified as SPAM automatically and never be audited.
请不要在评论中插入任何链接,否则将被自动归类为垃圾评论,且永远不会被提交给博主进行复审。

*