FindFirstFile 函数会尝试匹配短文件名和长文件名。这可能会产生一些令人惊讶的结果。例如,如果你查找 “*.htm” ,那么它会返回给你文件 “x.html” ,因为它的短文件名是 “X~1.HTM”。 这确实比较令人感到意外。
为什么 FindFirstFile 会匹配短文件名呢?它不应该只匹配长文件名吗?毕竟,只有旧的 16 位程序才会使用短文件名。
但这就是问题所在:16位程序才会使用短文件名。
通过称为通用Thunk 的方法,16 位程序可以加载 32 位 DLL 并调用它。Windows 95和Windows NT中的Windows 16位仿真层严重依赖通用Thunk,因此他们不必编写所有内容的两个版本。相反,16 位版本只是升级到 32 位版本。
但请注意,这意味着 32 位 DLL 将看到文件系统的两个不同视图,具体取决于它们是从 16 位进程还是 32 位进程托管的。
“然后让 FindFirstFile 函数检查其调用方是谁,并相应地更改其行为”,因为你无法信任返回地址,因此这种方法不会起作用。
即使解决了这个问题,你仍然会遇到跨进程边界的 16/32 互操作的问题。
例如,假设一个 16 位程序调用 WinExec(”记事本 X~1.HTM”)。32位记事本程序最好打开文件X~1.HTM,即使它是一个短文件名。此外,获取文件属性(如上次访问时间)的常用方法是使用文件名调用 FindFirstFile,因为 WIN32_FIND_DATA 结构将该信息作为查找数据的一部分返回。(注意:GetFileAttributesEx 是更好的选择,但该功能相对较新。如果 FindFirstFile 函数不适用于短文件名,则上述技巧对于跨 16/32 边界传递的短文件名将失败。
再举一个例子,假设 DLL 将文件名保存在进程外部的位置,例如配置文件、注册表或共享内存块。如果 16 位程序程序调用此 DLL,它将传递短文件名,而如果 32 位程序调用 DLL,它将传递长文件名。如果文件系统函数仅返回 32 位程序的长文件名,则在 32 位程序中运行的 DLL 副本将无法读取在 16 位程序中运行的 DLL 写入的数据。
总结
由于 API 是一个已经对外公开的调用规范,不可轻易修改,否则会破坏兼容性。为此在最新的操作系统上运行那些老程序,只能最大限度地保留现有 API 的外部接口。同时,通过增加新的 API 来支持操作系统上开发出来的新特性。这就说我们经常说的:对扩展开放,对修改关闭。
所以,”先知性” 是在规划高层设计的一项特殊能力。