TONT 33983 可我的 Visual Basic 是专业版!

原文链接:https://devblogs.microsoft.com/oldnewthing/20050930-10/?p=33983

Back in 1995, I was participating in a chat room on MSN on the subject of device driver development. One of the people in the chat room asked, “Can I write a device driver in Visual Basic?”

1995 年的某一天,我正在 MSN 的聊天室中参与关于设备驱动程序的开发。聊天室里有个人问道,『我能不能用 Visual Basic 来写设备驱动?』

I replied, “Windows 95 device drivers are typically written in low-level languages such as C or even assembly language.”

我回复他,『Windows 95 设备驱动通常是用底层语言来编写的,例如 C 语言,甚至是汇编。』

Undaunted, the person clarified: “But I have Visual Basic Professional.”

此人则毫无畏惧地澄清道:『可是我的 Visual Basic 是专业版。』

TONT 34283 为什么会有 WSASetLastError 这个函数?

原文链接:https://devblogs.microsoft.com/oldnewthing/20050908-19/?p=34283

Why does the function WSASetLastError exist when there is already the perfectly good function SetLastError?

为什么在已经有了 SetLastError 这么好的一个函数的情况下,还要再有一个 WSASetLastError 呢?

Actually, you know the answer too, if you sit down and think about it.

实际上,如果坐下来思考一番的话,你也已经知道答案了。

Winsock was originally developed to run on both 16-bit Windows and 32-bit Windows. Notice how the classic Winsock functions are based on window messages for asynchronous notifications. In the 16-bit world, there was no SetLastError function. Therefore, Winsock had to provide its own version for the 16-bit implementation. And since source code compatibility is important, there was a 32-bit version as well. Of course, the 32-bit version looks kind of stupid in retrospect if you aren’t aware of the 16-bit version.

Winsock 原本是设计同时运行在 16 位和 32 位的 Windows 上的,需要注意的是,传统的 Winsock 函数的运行依赖窗口消息来获取异步通知。在 16 位的世界里,并没有 SetLastError 这么个东西,因此,Winsock 需要为 16 位环境提供它自己版本的 SetLastError。同时,由于源代码兼容性是一件很重要的事情,也就有了 32 位的 WSASetLastError。当然了,如果你不了解有 16 位环境下的需求这件事的话,32 位版本下的它看上去就有那么点多余了。

TONT 34403 为什么默认的控制台代码页叫OEM?

原文链接:https://devblogs.microsoft.com/oldnewthing/20050829-00/?p=34403

Last year, we learned that the ANSI code page isn’t actually ANSI. Indeed, the OEM code page isn’t actually OEM either.

去年的时候,我们了解了一下 ANSI 代码页为什么实际上并不是 ANSI。实际上,OEM 代码页也并非 OEM。

Back in the days of MS-DOS, there was only one code page, namely, the code page that was provided by the original equipment manufacturer in the form of glyphs embedded in the character generator on the video card. When Windows came along, the so-called ANSI code page was introduced and the name “OEM” was used to refer to the MS-DOS code page. Michael Kaplan went into more detail earlier this year on the ANSI/OEM split.

在 MS-DOS 那个年代,实际上只有一个代码页,由原始设备制造商(original equipment manufacturer,OEM)以符号形式潜入在显示适配器的字符生成器中。后来有了 Windows 之后,就引入了所谓的 ANSI 代码页,而从 MS-DOS 继承而来的代码页就被叫做是 OEM 代码页了。Michael Kaplan 在其今年早些时候的博文中深入挖掘了一下这一分离过程(译注:链接已失效)。

Over the years, Windows has relied less and less on the character generator embedded in the video card, to the point where the term “OEM character set” no longer has anything to do with the original equipment manufacturer. It is just a convenient term to refer to “the character set used by MS-DOS and console programs.” Indeed, if you take a machine running US-English Windows (OEM code page 437) and install, say, Japanese Windows, then when you boot into Japanese Windows, you’ll find that you now have an OEM code page of 932.

多年过去,Windows 已经越来越少地依赖于潜入在显示适配器的字符生成器了,以至于『OEM字符集』这个概念也跟原始设备制造商越来越没什么关系了,而只是一种指代『由 MS-DOS 和控制台应用程序使用的字符集』的一种方便的称呼而已。实际上,如果你在一台运行美国英语版本 Windows(OEM代码页437)的机器上安装一个,比如说,日文版的 Windows,等你进入系统之后,就会发现系统当前的字符集是 OEM 932了。

TONT 34433 Windows 95 把收款机搞崩溃了

原文链接:https://devblogs.microsoft.com/oldnewthing/20050825-30/?p=34433

Not everything related to the Windows 95 launch went well. The St. Louis Post-Dispatch reported that a local CompUSA store found that their cash registers crashed at midnight, forcing eager customers to wait ninety minutes before the problem could be resolved. The cause: A bug in the cash register software which had lain undiscovered because the store had never stayed open past midnight before!

并不是所有与 Windows 95 发布的事情都进展顺利。据《圣路易斯邮报》所载,当地的一家 CompUSA 门店发现他们的收款机在午夜时分崩溃了,硬是让急不可耐的顾客们等了一个半小时才把问题解决。至于原因,则是因为收款机软件中的一个未被发现的bug,因为这家门店从来没有在午夜之后营业过,所以也就从来没有被发现!

(译注:以下两句因原文链接已失效,译来意义不大,仅作原文保留)

And there was the the launch of Mindows 95 in Hong Kong.

Not one to sit by and miss out on all the attention, Apple responded with its absolutely brilliant counter-advertisement.

TONT 34463 买下整间Egghead软件商城

原文链接:https://devblogs.microsoft.com/oldnewthing/20050824-11/?p=34463

During the development of Windows 95 (which released to the public ten years ago today), application compatibility was of course a very high priority. To make sure that coverage was as broad as possible, the development manager for Windows 95 took his pick-up truck, drove down to the local Egghead Software store (back when Egghead still existed), and bought one copy of every single PC program in the store.

在 Windows 95 开发期间(正好是十年前的今天(译注:本文成文时间2005年8月24日)向公众发布),应用程序兼容性自然是优先级非常高的一项事务。为了保证(Windows 95 的软件兼容性)覆盖面尽可能广泛,开发团队的经理开上了他的皮卡,到了本地的一家 Egghead 软件商城(当时还存在)(译注:Egghead Software 是美国的一家软件分销商,1984年至2001年间存续),把里面的每一种PC软件都买了一份。

He then returned to Microsoft, unloaded all the software onto tables in the cafeteria, and invited every member of the Windows 95 team to come in and take responsibility for up to two programs. The ground rules were that you had to install and run the program, use it like a normal end user, and file a bug against everything that doesn’t work right, even the minor stuff. (Of course, you had to provide the program to the person investigating the bug upon request.) In exchange for taking responsibility for ensuring that Windows 95 was compatible with your adopted programs, you got to keep them after Windows 95 shipped. If you did a good job with your two, you could come back for more.

然后他回到公司,把买来的所有软件倒在餐厅的桌子上,并邀请 Windows 95 团队的每个成员都来取走最多2种软件并对此负责。基本的原则是,成员应当安装并运行所拿到的软件,像一名普通的最终用户那样使用软件,并对所遇到的每一个不太对劲的问题提交一份bug报告,即便是最细微的地方也需要(当然,当提出要求时,同样也需要将程序本身提交给负责调查这个bug的人)。作为对确保成员所负责的应用程序最终能与 Windows 95 相兼容的努力的交换,等 Windows 95 发布后,成员可以将软件本体据为己有。如果搞定了手里的2个软件,还可以再来取走更多的副本。

The cafeteria was filled with Windows 95 team members, browsing through the boxes upon boxes of software like bargain-hunters at a flea market. And there were the inevitable “What’d you get?” comparisons afterwards.

餐厅里挤满了 Windows 95 团队的成员,如同在跳蚤市场里捡便宜的人那样在一大堆软件盒子里挑来拣去,并且不可避免地讨论着『你拿到啥了』这样的对话。

I picked up only one program, an English/German automatic translator. It ran fine but produced pretty bad translations. (Not that the quality of the translations was in any way the fault of Windows!)

我只拿到了一个软件,是一个英德自动翻译软件,它运行起来没什么问题,就是翻译的质量太糟糕了。(这软件翻译成那样可跟 Windows 一毛钱关系都没有!)

TONT 34513 Windows 95 的安装程序用了多少张软盘才装下?

原文链接:https://devblogs.microsoft.com/oldnewthing/20050819-10/?p=34513

Thirteen.

13张。

In case you were wondering.

如果你真那么想知道的话。

And those were thirteen of those special Distribution Media Format floppies, which are specially formatted to hold more data than a normal 1.44MB floppy disc. The high-capacity floppies reduced the floppy count by two, which resulted in a tremendous savings in cost of manufacturing and shipping.

并且这13张软盘都是所谓的『分发媒体格式』(Distribution Media Format)的软盘,经过特殊的格式化,可以存储比普通的1.44MB软盘更多的数据。这些高容量软盘让(一套Windows 95安装程序)所需的软盘数量减少了2张,从而在制造和运输的过程中减少了海量的成本。

(I’m sure there are the conspiracy-minded folks who think that DMF was invented as an anti-piracy measure. It wasn’t; it was a way to reduce the number of floppy disks. That the disks were difficult to copy was a side-effect, not a design goal.)

(我觉得肯定有些阴谋论者认为DMF软盘是某种反盗版措施,然而实际上并非如此,它只是一种减少软盘数量的方式而已。这些磁盘难以复制只是副作用,而不是设计目的。)

(For comparison, Windows 3.1 came on six floppies. Windows NT 3.1 came on twenty-two. And yesterday, one of my colleagues reminded me that Windows NT setup asked for the floppy disks out of order! I guess it never occurred to them that they could renumber the disks.)

(作为对比,Windows 3.1 用了6张软盘,Windows NT 3.1 用了22张。并且昨天,有个同事还告诉我 Windows NT 安装程序要求用户提供软盘的时候是不按顺序的!我觉得这个问题他们应该从来没有遇到过,因为他们可以给磁盘重新标号。)

TONT 34563 当人们要将安全漏洞作为功能的时候:静默安装未经认证的驱动

原文链接:https://devblogs.microsoft.com/oldnewthing/20050816-08/?p=34563

Probably the single greatest source of bluescreen crashes in Windows XP is buggy device drivers. Since drivers run in kernel mode, there is no higher authority checking what they’re doing. If some user-mode code runs amok and corrupts memory, it’s just corrupting its own memory. The process eventually crashes, but the system stays up. On the other hand, if a driver runs amok and corrupts memory, it’s corrupting your system and eventually your machine dies.

Windows XP 蓝屏崩溃的最大原因之一是有问题的设备驱动。由于驱动运行在内核模式下,已经没有更高级别的机制来监控它们在做什么了。如果一段用户模式下的代码发飙,破坏了内存数据,那它也只是破坏了它自己的内存段而已。其进程最终会崩溃,但整个系统还是好好的。另一方面,如果某个驱动程序发飙,破坏了内存数据,那它破坏的是整个系统,最终你的机器会停止运转。

In acknowledgement of the importance of having high-quality drivers, Windows XP warns you when an uncertified driver is being installed. Which leads to today’s topic, a question from a device driver author.

鉴于驱动高质量的重要性,Windows XP 会在安装未经认证的驱动时警告用户,这就引出了今天的话题,是一位来自某个设备驱动程序作者的提问:

When I try to install any driver, I get a User Consent Dialog box which tells the user that this is an unsigned driver. Is it possible to author a driver installation package that by-passes this user consent dialog box?

当我尝试安装驱动时,系统都会弹出一个请求用户允许的对话框,告诉用户正在安装一个未签名的驱动。有没有办法编写一种驱动安装包,能让系统不显示这个对话框?

The whole purpose of that dialog is to prevent the situation you desire from happening! [typo fixed 5pm] If you don’t want the warning dialog, submit your driver for certification. (For testing purposes, you can sign your drivers with the test root certificate and install the test root certificate before running your setup program. Of course, installing the test root certificate also causes the desktop to read “For test purposes only” as a reminder that your machine is now allowing test-signed drivers to be installed.)

这个对话框的存在意义,可正是阻止你所想要的这种事情的发生啊!如果你不想让这个对话框出现,那就把你的驱动提交认证就好。(如果是出于测试的目的,你可以将你的驱动用测试根证书签名,并且在运行你的安装程序之前安装这个测试根证书。当然,安装测试根证书会让桌面上冒出“仅供测试使用”的字样,用来提醒你你的机器目前允许安装测试签名的驱动。)

Driver writers, of course, find the certification process cumbersome and will do whatever they can to avoid it. Because, of course, if you submit your driver for certification, it might fail! This has led to varying degrees of shenanigans to trick the WHQL team into certifying a driver different from the one you intend to use. My favorite stunt was related to my by a colleague who was installing a video card driver whose setup program displayed a dialog that read, roughly, “After clicking OK, do not touch your keyboard or mouse while we prepare your system.” After you click OK, the setup program proceeds to move the mouse programmatically all over the screen, opening the Display control panel, clicking on the Advanced button, clicking through various other configuration dialogs, a flurry of activity for what seems like a half a minute. When faced with a setup program that does this, your natural reaction is to scream, “Aaaiiiiigh!”

而驱动的编写者们,自然而然地发现这个认证过程缓慢而冗长,继而想出各种各样的办法来避免之。毕竟,如果你把自己的驱动提交认证的话,还是有通不过的可能性的!这种可能性让开发者们想出了各种稀奇古怪的门路,让WHQL团队给你所提交的驱动进行认证,但实际发布的则不是那一个。我所最喜欢的一则是由我的同事提供的,当他安装某款显卡驱动的时候,安装程序弹出一个对话框,上面大体上写着这些内容:“点击OK后,在我们帮你为系统进行准备配置时,请不要操作键盘或鼠标。”点击OK之后,安装程序就开始以程序操作你的鼠标满屏幕跑,打开『显示』控制面板,点击『高级』按钮,然后这里那里点击很多配置项,一同忙乱下来大概要花半分钟左右。面对这样的安装程序,你的内心想必是在大喊『啊啊啊啊啊』的吧。

TONT 34623 为什么 Windows 的错误报告程序昵称叫『Dr. Watson』?

原文链接:https://devblogs.microsoft.com/oldnewthing/20050810-13/?p=34623

The nickname for the feature known as Windows Error Reporting is “Dr. Watson”. Where did that name come from?

Windows 的错误报告功能有个昵称叫『Dr. Watson』(华生博士),这个名字是从哪来的呢?

As you have probably guessed, The name Dr. Watson was inspired by the character of Dr. Watson, the assistant to Sherlock Holmes in the stories by Arthur Conan Doyle.

如你所想,『华生博士』这个名字是受亚瑟·柯南道尔笔下的夏洛克·福尔摩斯的助手华生博士启发而起的。

It is my understanding that the doctor was originally developed as part of Windows 3.0 beta testing. His job was to record data about application crashes to a file, so that the file could be uploaded and included with bug reports. The icon was (and continues to be) a friendly doctor using his stethoscope to investigate a problem.

据我所了解,Dr. Watson 原本是作为 Windows 3.0 的 beta 测试工具被开发出来的,其工作是将崩溃的应用程序的数据记录到文件,以便将其嵌入到bug报告中进行上传。Dr. Watson 的图标曾经(并且至今如此)是一位用听诊器在调查问题的、和善的博士。

The Doctor has remained true to the “capture information about an error” aspect of his job. In the meantime, the word “Watson” has expanded its meaning to encompass anonymous end-user feedback mechanisms in general, such as “Content Watson”. (But if you hear “Watson” by itself, the speaker is almost certainly talking about error reporting.)

Dr. Watson 的工作『获取关于错误的信息』方面的描述一直保持不变。与此同时,Watson 这个词的含义也被扩展,囊括了面向最终用户的匿名反馈事项,例如『Content Watson』这种用法。(不过如果你单独听到 Watson 这个词,那说话者多半肯定是在讨论错误报告这回事。)

TONT 34783 你所说的那个叫『网站』的东西是什么?

原文链接:https://devblogs.microsoft.com/oldnewthing/20050728-16/?p=34783

One reaction I’ve seen when people learn about all the compatibility work done in the Windows 95 kernel is to say,

当人们对 Windows 95 内核所作出的兼容性努力发表意见时,我所知的其中一条是:

Why not add code to the installer wizard [alas, page is now 404] which checks to see if you’re installing SimCity and, if so, informs you of a known design flaw, then asks you to visit Electronic Arts’ webpage for a patch?

为什么不在安装程序里加一行代码(可惜这个页面已经404了)(译注:所以这里就不再引用失效链接了),让它可以检测到你是不是正在安装《模拟城市》,如果是的话,就提醒你游戏里的bug,然后帮你打开EA的网站去下载补丁呢?

Let’s ignore the issue of the “installer wizard”; most people do not go through the Add and Remove Programs control panel to install programs, so any changes to that control panel wouldn’t have helped anyway.

这里我们先忽略『安装程序』这个说法,毕竟大多数人是不会跑到控制面板的『添加/删除程序』里去安装新应用的,所以对控制面板做出变动并没有什么帮助。

But what about detecting that you’re running SimCity and telling you to get a patch from Electronic Arts’ web site?

姑且说,系统能不能做到检测你开启了《模拟城市》,然后通知你去EA的网站上下载补丁呢?

Remember, this was 1993. Almost nobody had web sites. The big thing was the “Information Superhighway”. (Remember that? I don’t think it ever got built; the Internet sort of stole its thunder.) If you told somebody, “Go to Electronic Arts’ web site and download a patch”, you’d get a blank stare. What’s a “web site”? How do I access that from Prodigy? I don’t have a modem. Can you mail me their web site?

请记住,那是1993年,基本上没什么人开设了『网站』这种东西,那时候的热门话题叫『信息高速公路』。(还记得这个词吗?我反正没记得这东西建成了没有,『互联网』把它的风头全抢尽了。)如果那年头你跟别人说『去EA的网站上下个补丁』,得到的只能是一脸茫然:『网站』是嘛玩意?我怎么访问它?我家又没有调制解调器,你能把他们的网站寄给我吗?

In Windows XP, when Windows detects that you’re running a program with which it is fundamentally incompatible, you do get a pop-up window directing you to the company’s web site. But that’s because it’s now 2005 and even hermits living in caves have email addresses.

在 Windows XP 中,当 Windows 检测到你运行的程序存在完全不兼容的情况时,你的确会得到一项提示,将你导向开发这个软件的公司的网站。但这是因为这时已经是2005年了,就连住在山洞里的隐士都有电子邮件地址了。

In 1993, things were a little different.

而1993年的时候,事情可不太一样。

(Heck, even by 1995 things most people did not have Internet access and those few that did used modems. Requiring users to obtain Internet access in order to set the computer clock via NTP would have been rather presumptuous.)

(1995年的时候,大多数人都没法上网,而仅有的能上网的人倒的确都在用调制解调器。让用户上网就为了能通过NTP服务设置一下本机的时钟就更加扯淡了。)

TONT 34883 为什么 FindFirstFile 会同时查找短文件名?

原文链接:https://devblogs.microsoft.com/oldnewthing/20050720-16/?p=34883

The FindFirstFile function matches both the short and long names. This can produce somewhat surprising results. For example, if you ask for “*.htm”, this also gives you the file “x.html” since its short name is “X~1.HTM”.

FindFirstFile 函数会同时匹配短文件名和长文件名,有时这种设计会带来一些意料之外的结果。例如,如果你查找『*.htm』,x.html(译注:注意此处的扩展名是HTML,其在8.3形式下为HTM,感谢石樱灯笼在评论中指出)也会出现在结果中,因为它的短文件名是X~1.HTM。

Why does it bother matching short names? Shouldn’t it match only long names? After all, only old 16-bit programs use short names.

为什么要去匹配短文件名呢,只匹配长文件名不就够了吗?毕竟只有旧式的16位应用程序会用短文件名了。

But that’s the problem: 16-bit programs use short names.

然而这却正视问题所在:16位应用程序使用的是短文件名。

Through a process known as generic thunks, a 16-bit program can load a 32-bit DLL and call into it. Windows 95 and the Windows 16-bit emulation layer in Windows NT rely heavily on generic thunks so that they don’t have to write two versions of everything. Instead, the 16-bit version just thunks up to the 32-bit version.

通过名为通用 Thunk 的过程,16位应用程序可以加载32位的DLL并调用之。Windows 95 和 Windows NT 中的 16 位 Windows 模拟层对于通用 Thunk 重度依赖,这样才不必为各种各样的东西编写2个版本,而是让 16 位的调用直接与 32 位的相关调用进行联动。

Note, however, that this would mean that 32-bit DLLs would see two different views of the file system, depending on whether they are hosted from a 16-bit process or a 32-bit process.

然而需要注意的是,如此一来32位的DLL便对文件系统有了两种观察方式,具体取决于其宿主进程是16位还是32位。

“Then make the FindFirstFile function check to see who its caller is and change its behavior accordingly,” doesn’t fly because you can’t trust the return address.

『那就让 FindFirstFile 看看调用方是谁,然后执行不同的行为不就好了』,这种想法是不现实的,因为你无法信任返回地址。

Even if this problem were solved, you would still have the problem of 16/32 interop across the process boundary.

就算能解决这个问题,你还是要面对16/32位进程边界间互操作的问题。

For example, suppose a 16-bit program calls WinExec(“notepad X~1.HTM”). The 32-bit Notepad program had better open the file X~1.HTM even though it’s a short name. What’s more, a common way to get properties of a file such as its last access time is to call FindFirstFile with the file name, since the WIN32_FIND_DATA structure returns that information as part of the find data. (Note: GetFileAttributesEx is a better choice, but that function is comparatively new.) If the FindFirstFile function did not work for short file names, then the above trick would fail for short names passed across the 16/32 boundary.

例如,假设某个程序调用了WinExec(“notepad X~1.HTM”),那么32位的记事本最好是去打开X~1.HTM,即便这是个短文件名。此外,获取文件属性(例如文件的最后访问时间)的一种通常方式便是调用 FindFirstFile 并提供文件名,因为 WIN32_FIND_DATA 结构会将这类信息包含在返回中。(请注意:使用 GetFileAttributesEx 是更好的做法,不过这个函数相对来说还比较新就是了。)如果 FindFirstFile(在32位程序调用它的时候)不能使用短文件名,那么前述的做法就会失效,因为此时短文件名跨越了16/32位的边界。

As another example, suppose the DLL saves the file name in a location external to the process, say a configuration file, the registry, or a shared memory block. If a 16-bit program program calls into this DLL, it would pass short names, whereas if a 32-bit program calls into the DLL, it would pass long names. If the file system functions returned only long names for 32-bit programs, then the copy of the DLL running in a 32-bit program would not be able to read the data written by the DLL running in a 16-bit program.

另一个例子是,假设某个DLL将文件名保存在进程之外的某处,例如配置文件中、注册表中,或某个共享的内存区域里。如果16位应用程序调用了这个DLL,那么它传入的就是短文件名,而32位应用程序调用时则会传入长文件名。如果文件系统函数只为32位应用程序返回长文件名,那么运行在32位应用程序下的这个DLL就无法读取由16位应用程序调用其时写入的数据了。