楔子
今天来说一则古老的历史问题。
16位的”影子DLL”
当Win9x尝试加载一个32位的DLL并需要让外界访问其中的资源时,它会创建一个对应的16位的”影子”DLL,这样使得16位的代码(例如USER)能访问其中的资源。
这个影子DLL实际上是一个16位的资源DLL,它是从其对应的32位DLL中转化而来。具体来说,就是系统将32位DLL中的资源复制出一份出来,然后转化为对应的16位的格式。如果发生了一些状况,比如某些资源无法被转化为16位的格式,那么,这个DLL加载就会失败。
16位的资源文件通过DLL级的shift value和一个16位资源相关的scaled size来确定了资源的大小。有点复杂,我们举个例子。如果shift value是2,scaled size是8,那么实际的资源的大小将会是:8 << 2 = 32。
Win95的Bug
Win95在计算scaled size时存在一个Bug。 因为一个32位的DLL可能包含超过64K的资源,如果Win95内核决定使用功能一个非0的shift value来计算资源的大小,那么它会将一个32位的值转换为一个16位的值,并向下取整。 因此,举个例子。如果资源大小为65537并且shift value是1,那么计算出来的值将会是:65537 >> 1 = 32768。然后将其再转换回来,结果是:32768 >> 1 = 65536。注意了这个值是非常小的 ,资源中的最后一个字节将会被截断。
这个Bug引发的结果
结果就是,如果你的32位DLL包含超过65K的资源,那么你必须将这些资源进行打包压缩一下,防止资源被截断。从上面的例子来说,就是你需要压缩资源至65538字节,那么转换的值为32769,再转换回去的值还是65538。
我相信这个Bug在Win98中已经得到修复,但我不太确定。
以下是你还可能碰到的其他的16位资源文件的问题:
> 顺序化的资源ID不能超过32767
> 命名化的资源名称的总长度不能超过65535(每一个资源名称中字符算一个字节,最后加一)。命名化的资源在Win1.0时就被视为是一个坏主意。所以,还是尽量变使用它们。
总结
这只是一个古老的历史问题,虽然它早就被修复了,但是,还是值得记录一下。
就当是缅怀一下。