Erroneous assumptions - [2004-04-05]
有人可能注意过,几乎所有Win32 API文档对返回值的描述类似这样
成功时返回NO_ERROR,失败时返回下列错误码之一
ERROR_INVALID_PARAMETER (关于无效参数的描述)
Other (参看WinError.h)
无法想像有多少人抱怨过上述对返回值的描述,微软究竟为啥不能在文档中直接枚举所有错误码?他们是傻,还是不聪明呢?
其实答案很简单,过去我们被坑过,我们不想再被坑一把。我桌上的纪念品中有本MS-DOS 2.0参考手册,微软于1984年出版。在第1-143页,有个创建句柄的API,这是DOS版的open()函数。该API文档枚举了当时所有的错误码
AX可取值有
3 = 找不到路径
4 = 打开的文件太多
5 = 拒绝访问
微软和IBM公布了所有DOS调用的所有返回值信息,我们跟客户说,INT 21的0x3D号调用只有三种返回值(3、4、5)。你知道吗,客户相信我们,他们基于这个说法开发应用程序。
好吧,随之而来的是DOS 3.1,它增加了对网络的支持,于是新增了一些失败原因,比如,"未找到网络路径"(文件在服务器上但服务器下线了),"共享冲突"(有人以排他方式打开了一个共享文件,导致他人打开失败)。
起初DOS 3.1通过AX返回新的错误码。微软以为绝大多数程序员足够聪明,知道将来会出现3、4、5之外的新的错误码。我们开始测试DOS 3.1的兼容性,发现这个假设大错特错。已有的应用程序左崩崩、右崩崩,每个被测应用都崩了。为啥?因为微软和IBM告诉这些应用的开发者,他们只会得到3、4、5三种错误码。当年内存非常昂贵,他们不想编写容错性更强的代码,那样太费内存。当你的应用跑在64KB内存的主机上时,容错性只是可选项。
为了保持向后兼容性,微软只好为DOS 3.1设计一种称为"DOS错误映射表"的技术,它将一个更广范围的错误码通过N对3映射到DOS 2.0的3种错误码中。为了获取更精准的新错误码,应用可以额外调用一个新的API(Get Extended Error)。
这项技术仍然存在于Longhorn中,我前几天还去查看了一下源码,在NTVDM相关组件中,不在Win32组件中。不管怎么样,它还活着,而且很可能我们永远无法摆脱它。至少在我们丢弃对16位DOS的支持之前,我们无法摆脱它,这不会很快发生。
从此,微软再也不文档化API返回值的所有错误码,由此将处理潜在出现新错误码的责任从微软转嫁给应用开发人员。
scz: 当年我调用过(Get Extended Error),原来这种设计是为了向后兼容性。。。