TONT 35713 当人们要将安全漏洞作为功能的时候:窃取密码

原文链接:https://devblogs.microsoft.com/oldnewthing/20050504-52/?p=35713

Sometimes people ask for features that are such blatant security holes I don’t know what they were thinking.

有些时候,有些人提出的功能需求完全就是安全漏洞,真不知道这些人脑子里都在想什么。

Is there a way to get the current user’s password? I have a program that does some stuff, then reboots the system, and I want to have the current user’s password so I can log that user back in when I’m done, then my program can resume its operation.

有没有办法获取当前用户的密码呢?我的程序会进行一些操作,然后重新启动系统,这时候我希望能获得用户的密码,这样重启完成后就能替用户进行登录,然后我的程序就能继续执行剩下的操作了。

(Sometimes they don’t bother explaining why they need the user’s password; they just ask for it.)

(有时候这些人连为什么需要用户的密码都懒得解释,就只是要而已。)

Imagine the fantastic security hole if this were possible. Anybody could write a program that steals your password without even having to trick you into typing it. They would just call the imaginary GetPasswordOfCurrentUser function and bingo! they have your password.

想象一下如果这件事成为可能的话,会产生一个多么美妙的安全漏洞。任何人都可以写一段程序来窃取你的密码,甚至不需要欺骗你把密码输进去,只需要调用那个虚构的 GetPasswordOfCurrentUser 方法就好了,一转眼,他们就拥有了你的密码。

For another angle on credential-stealing, read Larry Osterman‘s discussion of why delegation doesn’t work over the network.

或者也可以换个角度来观察凭据窃取这个问题,可以读一读  Larry Osterman 关于为什么代理认证在(内部)网络上行不通的文章。

Even if you didn’t want the password itself but merely some sort of “cookie” that could be used to log the user on later, you still have a security hole. Let’s call this imaginary function GetPasswordCookieOfCurrentUser; it returns a “cookie” that can be used to log the user on instead of using their password.

即便你不是想要密码本身,只是想要个某种形式的『Cookie』用于稍后替用户登录,这样操作同样也是一个安全漏洞。姑且将这个想象中的方法叫做 GetPasswordCookieOfCurrentUser,调用之会返回一个『Cookie』可以在稍后用于替用户登录,而不是直接返回用户的密码。

This is just a thinly-disguised GetPasswordOfCurrentUser because that “cookie” is equivalent to a password. Log on with the cookie and you are now that person.

这不过是前述的 GetPasswordOfCurrentUser 稍稍改头换面了一下而已,因为这个『Cookie』等同于密码,用这个『Cookie』登录之后你就是用户本人了。

(译注:Windows 10 看上去已经有了这篇15年前的文章描述的功能了——设置—账户—登录选项—『更新或重启后,使用我的登录信息自动完成设备设置并重新打开我的应用』,但仅限于系统更新或由系统发起的设备配置,而不是像这篇文章说的那样可以由第三方程序使用,且如果本机加入了域或应用了组策略,则该功能不可用。点击这里查看官方说明。)

Day 5205 关于『饭碗儿』的一些说明

由于饭否的页面及API设计,有关『饭碗儿』账号的一些说明写在个人简介中相当局促,在账号开设近5年后的今天,终于还是决定单列一个页面,对一些问题进行说明。

一、『饭碗儿』是什么

『饭碗儿』是一个对饭否『随便看看』栏目的统计账号。由于『随便看看』包含来自全站公开消息中的随机的20条左右的数据,在一定程度上可以作为饭否站内消息概况的一个缩影。

很多对『饭碗儿』的疑问都来源于对上述概念的不完整理解,如果您对『饭碗儿』的数据有疑问,请继续往下看。

二、『饭碗儿』的数据生成过程

『饭碗儿』的统计数据来源于对『随便看看』的数据采集。每个整秒分钟(如:8:00:00,或:13:45:00),『饭碗儿』的后台服务都会对『随便看看』进行一次数据采集,并将全量数据保存在本地备用。

每周一(理论上),『饭碗儿』的管理者(我)会用事先写好的工具将上周七天的数据进行统计,包含如下两类数据:

(一)客户端使用情况:在数据中查找名称『完全不同』的API名称(即『通过____发送』的中间部分,如:网页、御饭 iPhone 等等)进行计数统计。

(二)公共TL话痨50强:在数据中查找发送人、消息内容、发送时间完全不同的饭否消息,统计其所属的发送人出现的次数。

关于第(一)条,一个普通用户不容易注意到的细节是,API 返回中的 API 名称,除饭否官方 API 外(如『网页』,即饭否的PC端网页),原则上所有API都必填一个应用说明页面的URL,采集时,这类API名称会体现为:<a href=”http(s)://应用说明页面网址/”>API名称</a>。对于去掉<a>标签后名称相同的API,统计时会按照两条数据对待。

统计好之后,管理者还会对按要求提交排除申请用户和API名称进行处理,将这些数据进行剔除,最后制成图表,发送到账号上。

三、关于『饭碗儿』的一些疑问

倘若仔细读过了前述说明,仍未能解答您的疑问的话,这里有一些饭否用户对『饭碗儿』的一些问题,可供参考。

如您仍有其它下列未列出的问题,可在本文下方留言提问,确实未予回答的,本人会进行回复。

(〇)星期一了,怎么没发统计数据?

答:平日工作较忙,如未能准时发布,后面会尽量补上,请理解。未制作自动制图流程,因为我懒。此外,由于服务端托管环境的不稳定性(如系统崩溃、机房停电等),部分期数可能无法发布,如有时间,会登录饭碗儿账号进行说明,也可能没有解释。

(一)随便统计别人发过的消息次数,你是不是变态?

答:『随便看看』中的消息,均由饭否官方通过自动的形式公开向登录用户进行展示,『饭碗儿』无法控制饭否『随便看看』功能展示的信息,仅对这些公开数据进行采集,且仅作为统计原始数据使用,没有将这些消息的内容进行转载、修改或任何妨害消息原发布者隐私权的行为,如果您认为『饭碗儿』的行为侵犯了您的个人权益,请参考下述第(二)条的方式,向『饭碗儿』主动提交从统计数据中移除的请求,否则视为同意『饭碗儿』对您出现在『随便看看』中消息的采集行为,『饭碗儿』不对任何人的玻璃心行为负责。如您仍有疑问,请恰饭否官方或法律人士进行咨询,『饭碗儿』保留对不合理的请求进行无视、在『饭碗儿』账号上进行公开发布的权利。

(二)因为个人原因,我不想让我的账号或API名称出现在『饭碗儿』的统计数据中,应该怎么做?

答:请通过饭否的『私信』功能,向『饭碗儿』发送私信,说明您(或您的API名称,此处建议您提供带有对应API名称的示例公开消息,以便准确定位)不想在『饭碗儿』的统计数据中出现即可,无需提供理由,除此之外的方式均视为无效,不予受理。『饭碗儿』将从消息收到之日起(视乎『饭碗儿』所有人登录饭否网查看私信之时间为准,不以消息发出时间为准)永久性地将您或您的API名称从『饭碗儿』的后续统计数据中移除。此外,由于饭否的功能限制,已发送的消息无法进行修改,故若已发送的统计数据中包含您或您提供的API名称,则无法进行移除,望知悉。

(三)为什么我说了那么多的话(为什么我的应用明明那么多人用),却没有上『饭碗儿』的『公共TL话痨50强』(客户端使用情况)的榜单?

答:请注意『饭碗儿』只是对『随便看看』数据的统计,由于饭否的『随便看看』是对全站公开数据的随机抽取,以上两种状况发生的原因有:(1)在每分钟采集时,『随便看看』中没有抽到您(的API)的消息;(2)统计期间您打开了隐私保护(即所谓的『上锁』),使得您的消息不会出现在『随便看看』中。

(四)为什么我(的API)在统计期间明明发了10000条消息,却只给我算了1000条?『饭碗儿』是不是把我拉黑了?

答:请注意『饭碗儿』只是对『随便看看』数据的统计,由于饭否的『随便看看』是对全站公开数据的随机抽取,数据存在一定的随机性,且『饭碗儿』并非针对单个用户(或API)个体进行数据统计,故只能代表您(的API)在『随便看看』中每整分钟采集时的情况,仅供参考,不能代表精确的情况。此外,『饭碗儿』从未也不会主动拉黑任何人或任何API名称,除非用户或API名称的持有人通过上述第(二)条中描述的方式提起请求,此时『饭碗儿』会按要求对相应的数据条目进行移除。

(五)为什么我(的API)发了10000条消息,然后又全删掉了,统计的时候还是给我算了8000条消息?

答:请注意『饭碗儿』只是对『随便看看』数据的统计,数据来自每个整分钟对『随便看看』进行采集,但不会后期再次验证拉取消息的删除情况,故拉取数据时已发送的消息均会列入统计。

(六)我有几个API名称,能不能帮我合成一条统计记录?

答:维护API名称是开发者的责任,不提供此服务。

(七)为什么客户端列表中有两个『网页』?

答:数量较多者为饭否官方的“网页版”,较少者为某系列机器人的API名称(自2021年起,因对应服务停运,仅保留1个Bot运行,消息数量下降,基本已不会再产生混淆)。

四、一点点『饭碗儿』的历史

『饭碗儿』账号建立于2015年10月12日,起初是因对饭否全站的消息词频等数据感兴趣而设立的。

最开始时,『饭碗儿』曾对客户端统计情况、公共TL话痨50强、消息时段分布及词频进行统计。后来经过一段时间的运行,消息时段分布因每次都几乎没有差别,没有太大意义而取消掉了,词频云则由于未能找到物美价廉的分词API而作罢,而余下的两种类型,则一直运行到今天。

『饭碗儿』运行至今,除了一大堆娱乐性图表外,还积累了另一份数据:2015年11月至今的饭否『随便看看』每周1.08万次的采集。尽管该数据因硬件故障、API故障、被意外封停等问题并非全量,但在某种意义上也是见证了饭否多年来公开的欢声笑语。

TONT 35853 当人们要将安全漏洞作为功能的时候:在资源管理器中隐藏文件

原文链接:https://devblogs.microsoft.com/oldnewthing/20050419-50/?p=35853

By default, Explorer does not show files that have the FILE_ATTRIBUTE_HIDDEN flag, since somebody went out of their way to hide those files from view.

通常情况下,资源管理器不会显示带有 FILE_ATTRIBUTE_HIDDEN 标签的文件,因为有人特意将这些文件在视图中隐藏了。

You can, of course, ask that such files be shown anyway by going to Folder Options and selecting “Show hidden files and folders”. This shows files and folders even if they are marked as FILE_ATTRIBUTE_HIDDEN.

当然,你也可以刻意要求将这些文件显示出来,方法是在『文件夹选项』中勾选『显示隐藏的文件和文件夹』。这样即便被标记了 FILE_ATTRIBUTE_HIDDEN 标签的文件和文件夹也会被显示出来。

On the other hand, files that are marked as both FILE_ATTRIBUTE_HIDDEN and FILE_ATTRIBUTE_SYSTEM remain hidden from view. These are typically files that involved in the plumbing of the operating system, messing with which can cause various types of “excitement”. Files like the page file, folder configuration files, and the System Volume Information folder.

另一方面,同时具有 FILE_ATTRIBUTE_HIDDEN  和 FILE_ATTRIBUTE_SYSTEM 标签的文件在视图中仍然是隐藏的,这类文件通常是对系统来说至关重要的,对这些文件乱来会造成各种各样『激动人心』的事情,例如页面文件(译注:虚拟内存)、文件夹的配置文件、以及卷信息(System Volumn Information)文件夹。

If you want to see those files, too, then you can uncheck “Hide protected operating system files”.

如果你想看到这些文件,可以选择取消勾选『隐藏受保护的系统文件』。

Let’s look at how far this game of hide/show ping-pong has gone:

现在我们来看看这场隐藏与显示猫鼠游戏走到了什么地步:

Show(显示) Hide(隐藏)
1. Normal file(普通文件)
2. Hidden file(带有隐藏属性的文件)
3. “Show hidden files”(『显示隐藏的文件(和文件夹)』)
4. Hidden + System(带有隐藏+系统属性的文件(和文件夹))
5. “Show protected
operating system files”(『显示受保护的系统文件』)

You’d think this would be the end of the hide/show arms race, but apparently some people want to add a sixth level and make something invisible to Explorer, overriding the five existing levels.

你可能以为这场隐藏与现实的军备竞赛就到此为止了,但很显然,有人还想再加一个第六级别,让某些东西在资源管理器中不可见,凌驾于现有的五层设计之上。

At some point this back-and-forth has to stop, and for now, it has stopped at level five. Adding just a sixth level would create a security hole, because it would allow a file to hide from the user. As a matter of security, a sufficiently-privileged user must always have a way of seeing what is there or at least know that there is something there that can’t be seen. Nothing can be undetectably invisible.

这种你来我往的竞赛到了某种程度就应该打住了,而目前则停在了第五级上。只增加一个第六级会催生一个安全漏洞,因为那样就会允许某个文件对用户不可见。出于安全考虑,某个具备足够权限的用户必须总是有办法看到某处有什么东西,或者至少知道那里有什么目前看不到的东西。任何东西完全隐形、无法被检测到是不可以的。

If you add a sixth level that lets a file hide from level five, then there must be a level seven that reveals it.

如果你真的增加了在第五级的情况下看不到的第六级,那么就必须有第七级可以解除这种限制。

TONT 36053 程序向你抛出了一个问题,但如果作答的话就会爆炸

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

JeffDav’s story of a program that didn’t like it when he told it where to install reminded me of another program that we dealt with during Windows 95 development.

JeffDav 上那篇关于某个不喜欢被用户指定安装位置的程序的故事,让我想起我们在 Windows 95 开发过程中曾经面对的另一个程序。

This was a big-name program developed by one of the biggest-of-the-big name software companies. Let’s give this program the imaginary name “LitWare”. Its setup program asked you where you wanted the program to be installed, and it suggested “C:\LITWARE”. If you accepted the default, then everything proceeded normally.

那个程序是某个顶尖有名的大公司开发的某个大品牌,这里我们先给它起个虚构的名字,叫 LitWare。这个应用的安装程序会询问你要将其安装到哪个位置,并顺带建议安装到『C:\LITWARE』。如果你直接采纳这个默认值,那么一切都会很顺利。

However, if you changed the default to anything else, the setup program ran to completion, but the program itself wouldn’t run.

然而,如果你把这个默认值改成其它的路径,那么虽然可以完成安装,但程序本身则无法启动。

Because the program contained the hard-coded path “C:\LITWARE” and insisted that it find its support files in that directory.

因为程序里将路径『C:\LITWARE』进行了硬编码,并坚持在那个路径下面寻找程序的支持文件。

At least Jeff’s program realized that it was about to be installed into a directory where it would fail to work!

至少 Jeff 提到的那个程序还晓得自己要被安装到会造成它没法工作的目录里去呢!

 

附:文章开头提到的 JeffDav 上的文章:《安装的麻烦》(Installation woes)

原文链接:https://docs.microsoft.com/en-us/archive/blogs/jeffdav/installation-woes

After successfully getting Windows XP SP2 installed on my laptop, I started installing other software.

在成功把 Windows XP SP2 安装到我笔记本上之后,我开始安装其它的程序。

This post has nothing to do with IE, but I need to vent.

这篇博文跟 IE 没什么关系,但我还是得发泄一下。

Nameless 3rd Party App: Where do you want to install me? How about c:\nameless?

某第三方应用:你要把我安装到什么地方?C:\nameless 这个路径怎么样?

Jeffdav: How about c:\program files\nameless?

Jeffdav:C:\Program Files\nameless 怎么样?

Nameless 3rd Party App: It is a bad idea to install me somewhere with spaces in the path. Continue anyway?

某第三方应用:把我装到路径里有空格的位置可不是个好主意,还是要继续吗?

Jeffdav: No. Lame. At least it knows it is lame and told me while I still have a chance to do something about it.

Jeffdav:不,算了吧。至少它还知道这样会出事,把这件事告诉了我,让我还有机会做点改变。

Jeffdav: Okay, fine, c:\nameless.

Jeffdav:行吧,那就这样,C:\nameless。

(译注:下面是另一个故事)

Nameless Microsoft App: Installing…

某微软应用:正在安装……

Nameless Microsoft App: Installing… <30 minutes later>

某微软应用:正在安装……(30分钟之后)

Microsoft Windows: You have lost your connection to the wireless LAN! (I was walking to a meeting.)

Windows:无线网络连接不可用!(我正在端着笔记本去开会的路上)

Nameless Microsoft App: Internal Error 3452. [OK]

某微软应用:内部错误3452。(点OK)

Microsoft Windows: You have reconnected to the wireless LAN!

Windows:无线网络已连接!

Jeffdav: <clicks OK>

Jeffdav:(点OK)

Nameless Microsoft App: Uninstalling…

某微软应用:正在卸载……

Nameless Microsoft App: Thanks for playing. Please start from the beginning again.

某微软应用:胜败乃兵家常事,大侠请重新来过。

Of course I did have success stories. Windows was easy to install off the slipstream CD. Putty, as always, was easy to install since setup for putty is simply xcopy.

当然我也成功安装过其它的程序。Windows 从整合好的光盘上安装很简单。Putty 则是一如既往的简单,毕竟只是一行 xcopy 的事。

The moral of this story, I guess, is that Setup is Hard.

我想,这个故事的寓意大概是,安装这件事真难啊。

TONT 36183 窗体不是便宜的对象

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

(译注:我深知这一篇的翻译质量应该很差,看不下去的话请直接跳过……)

Although Windows is centered around, well, windows, a window itself is not a cheap object. What’s more, the tight memory constraints of systems of 1985 forced various design decisions.

尽管 Windows 是围绕着窗体(windows)设计的,不过窗体并不是便宜大把的对象。此外,1985年硬件配置中紧俏的内存限制催生了很多被迫的设计决定。

Let’s take for example the design of the list box control. In a modern design, you might design the list box control as accepting a list of child windows, each of which represents an entry in the list. A list box with 20,000 items would have 20,000 child windows.

以 Listbox 控件的设计为例。在如今的设计理念中,你可能会将其设计为包含一列子窗体的控件,每个子窗体代表列表中的一个条目。一个拥有20000项条目的 Listbox 就会有20000个子窗体。

That would have been completely laughable in 1985.

这种设计在1985年会让人笑掉大牙。

Recall that Windows was built around a 16-bit processor. Window handles were 16-bit values and internally were just near pointers into a 64K heap. A window object was 88 bytes (I counted), which means that you could squeeze in a maximum of 700 or so before you ran out of memory. What’s more, menus hung out in this same 64K heap, so the actual limit was much lower.

回忆一下,当时 Windows 是围绕16位处理器设计的。窗体句柄是一系列16位的值,在内部则表现为一个 64K 堆中相邻的指针。一个窗体对象要用掉88个字节(我数过了),这就意味着你最多能在内存里塞下700个窗体,再塞就要内存溢出了。另外,菜单也在同一个 64K 堆中,故而实际的上限可能会更低。

Even if the window manager internally used a heap larger than 64K (which Windows 95 did), 20,000 windows comes out to over 1.5MB. Since the 8086 had a maximum address space of 1MB, even if you devoted every single byte of memory to window objects, you’d still not have enough memory.

即便窗体管理器在内部使用的是一个大于 64K 的堆(Windows 95即是如此),20000个窗体也要消耗将近 1.5MB 的空间。由于 8086 处理器的地址空间上限是 1MB,就算你将内存的每一个字节都贡献给窗体对象使用,还是没有足够的内存可以用。

Furthermore, making each list box item a window means that every list box would be a variable-height list box, which carries with it the complexity of managing a container with variable-height items. This goes against two general principles of API design: (1) simple things should be simple, and (2) “pay-for-play”, that if you are doing the simple thing, you shouldn’t have to pay the cost of the complex thing.

除此之外,让每一个 Listbox 的项目都作为一个窗体,意味着每个 Listbox 都会是高度可变的,这就带来了管理包含着可变高度项目的容器的复杂性。如此的设计违背了 API 设计的两项基本原则:(1)简单的事物就应该简单,以及(2)『办多少事花多少钱』,也就是如果事情本身就很简单,便不应当为复杂的事情付出代价。

Filling a list box with actual windows also would have made the “virtual list box” design significantly trickier. With the current design, you can say, “There are a million items” without actually having to create them.

将一个 Listbox 填满事实意义上的窗体,也会将这个『虚拟 Listbox』的设计变得陡然复杂起来。按照其目前的设计,你可以声明『列表中有一百万项』,但不必实际去创建这么多项目。

(This is also why the window space is divided into “client” and “non-client” areas rather than making the non-client area consist of little child windows.)

(这也是为什么窗体控件被分割为『工作区』和『非工作区』,而不是让非工作区也填满了小小的子窗体的缘故。)

To maintain compatibility with 16-bit Windows programs (which still run on Windows XP thanks to the WOW layer), there cannot be more than 65536 window handles in the system, because any more than that would prevent 16-bit programs from being able to talk meaningfully about windows. (Once you create your 65537’th window, there will be two windows with the same 16-bit handle value, thanks to the pigeonhole principle.)

为了维持与16位Windows应用程序的兼容性(鉴于WOW(译注:Windows-On-Windows,在新版Windows上为面向旧版系统设计的应用程序提供有限兼容性的兼容层,此处为32位系统兼容16位应用程序)层,这些程序在 Windows XP 上仍然可用),系统中的窗体句柄不能超过65536个,因为超过这个限制会阻止16位应用程序与系统对窗体进行有意义的沟通。(一旦创建了第65537个窗体,就会出现具有相同句柄值的两个窗体——感谢鸽巢原理(译注:又叫抽屉原理,指如果尝试将n+1个元素放进n个集合中,那么必然有一个集合中包含2个元素)的存在。)

(And yes, 16/32-bit interoperability is still important even today.)

(另外没错,16/32位应用程序的交互操作性,时至今日仍然很重要。)

With a limit of 65536 window handles, your directory with 100,000 files in it would be in serious trouble.

鉴于65535个窗体句柄上限的存在,你那拥有10万个文件的目录(如果按照前面那样嵌套小窗体的设计)就会有大麻烦了。

The cost of a window object has grown over time, as new features get added to the window manager. Today it’s even heftier than the svelte 88 bytes of yesteryear. It is to your advantage not to create more windows than necessary.

随着新功能不断加入窗体管理器,窗体对象的成本也在不断攀升。如今窗体数据的健壮程度已与当年那个苗条的88字节大小不可同日而语,而不要创建多于必要的窗体的责任就落在了你的肩上。

If your application design has you creating thousands of windows for sub-objects, you should consider moving to a windowless model, like Internet Explorer, Word, list boxes, treeview, listview, and even our scrollbar sample program. By going windowless, you shed the system overhead of a full window handle, with all the baggage that comes with it. Since window handles are visible to all processes, there is a lot of overhead associated with centrally managing the window list. If you go windowless, then the only program that can access your content is you. You don’t have to worry about marshalling, cross-process synchronization, Unicode/ANSI translation, external subclassing, hooks… And you can use a gigabyte of memory to keep track of your windowless data if that’s what you want, since your windowless controls don’t affect any other processes. The fact that window handles are accessible to other processes imposes a practical limit on how many of them can be created without impacting the system as a whole.

如果你的程序设计需要你创建成千上万个用于内部对象的窗体,你应当考虑迁移到无窗体的模型,就像 Internet Explorer、Word、Listbox、TreeView、ListView,甚至我们的滚动条示例程序那样。通过使用无窗体设计,你的程序向系统展示的就只有一个完整的窗体句柄,里面包含着所有大大小小的元素。由于窗体句柄是对所有进程可见的,对于集中管理的窗体列表来说负担是很重的。如果采用无窗体设计,那么唯一可以访问窗体中内容的就是你自己。你不必担心 Marshalling、跨进程同步、Unicode/ANSI 转换、外部子类、钩子…… 等等的麻烦事。另外如果你愿意,动用一个G的内存来跟踪你的无窗体模型下的内容也是刻意的,因为你的无窗体模型中的控件不会影响其它进程。由于窗体句柄对其他进程是可见的,也就对可以创建多少个窗体句柄而不会对系统整体产生重大影响这一事实施加了影响。

I believe that WinFX uses the “everything on the screen is an element” model. It is my understanding that they’ve built a windowless framework so you don’t have to. (I’m not sure about this, though, not being a WinFX person myself.)

我相信 WinFX 利用了『屏幕上的一切都是元素』这种模型,我的理解是他们构建了一个无窗体框架,以便你不用再从头造一遍轮子。(尽管对此我并不确定,毕竟我不是相关人士。)

TONT 36363 两则有关 Windows XP 的『Comments?』按钮的回忆

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

In beta versions of Windows XP, there was special code in the window manager to give every window a link in the upper right corner called “Comments?” which if clicked on displayed a dialog that allowed you to submit feedback to Microsoft about that window.

在 Windows XP 的beta 版本中,窗口管理器里有一段特别设计的代码,用来给每个窗口的右上角添加一个写作『Comments?』(有意见?)的链接,点击它会显示一个对话框,用于向微软提交关于那个窗口的反馈意见。

Since this was a beta release, there was no anonymity when you submitted feedback. (You signed away your anonymity when you agreed to the special beta license agreement and typed in your beta ID number.) Yet we got more than one feedback submission that begin, “Hi, I pirated this copy of Windows XP, and here’s some feedback.”

鉴于这是 beta 版,提交反馈时是没有什么匿名性可言的。(当你签署那张特别的 beta 授权协议并录入了你的 beta ID 时,你就已经让出让了你的匿名权。)不过我们还是收到了不止一份反馈,开头就是:『嗨,我这份 Windows XP 是盗版的,以下是我的反馈。』

In its initial incarnation, the word in the title bar was “Lame”, but people with a weaker sense of humor changed it to the less confrontational “Comments?”. The name “Lame” came from a recurring sketch on local comedy show Almost Live! called “The Lame List, or What’s Weak This Week (brought to you with the help of Seattle’s Heavy Metal community)”.

一开始的时候,标题栏里那个链接写的是『Lame』(跛的,瘸的),不过有个没太有幽默感的人把它换成了比较不具有挑衅性的『Comments?』。(译注:最后一句实在没看懂,但应该不影响对全文的理解,望看懂的朋友赐教。)

TONT 36483 为什么最小化的窗口具有形式上的160×31的尺寸?

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

We discussed a few months ago the issue of where windows minimized to before the taskbar was invented. In the modern taskbar world, why do minimized windows have an apparent size of 160×31?

几个月前,我们讨论过在任务栏发明之前的最小化窗口的问题。那么在如今任务栏一统天下的时代,为什么最小化的窗口会有一个形式上的160×31的尺寸呢?

The size isn’t just apparent. That’s really their size. You can see them, for example, if you fire up a program that uses the Multiple Document Interface.

这个尺寸不光是形式上的,实际上也是如此。你可以通过一些方式观察到这一点,例如启动一个食用了多文档界面(MDI)的程序。

(译注:原本这里有一张图片,但已经失效,请运用你的想象力)

Observe the appearance of the window “Book1”. This is a minimized window (though minimized to its MDI host rather than to the desktop). With the introduction of Windows Explorer, which put files on the desktop in the form of icons, it became necessary to change the appearance of minimized windows in order to avoid confusing a minimized program icon from a desktop icon. A minimized program, therefore, took the form of a miniature title bar.

观察这个叫『Book1』的窗口的外观。这是一个最小化的窗口(尽管是最小化到其MDI顶层窗口而不是桌面)。在引入了Windows资源管理器之后,桌面上允许以图标的形式放置文件了,修改最小化窗口的形式便变得有必要起来,以防人们将最小化的程序图标与文件图标相混淆(译注:Windows 95之前版本的Windows没有任务栏,最小化的程序会缩小为『桌面』上的一个图标,这里的桌面指的是『程序管理器』背后的整个屏幕空间,与Windows 95之后的『桌面』并不是同一个概念)。由此,最小化的程序使用了缩小的标题栏的形式。

The programming interface to minimized windows remained the same, for compatibility reasons. (And please let’s just agree to disagree on whether backwards compatibility is a good thing or not.) That’s why the function to tell whether a window is minimized continues to be called IsIconic, the message you receive when someone tries to restore a minimized program is still called WM_QUERYOPEN, and the OpenIcon function can still be used to “open” a minimized “icon”. All even though minimized windows haven’t looked like icons for nearly ten years.

面向最小化窗口的编程接口(与旧版Windows)保持了一致,这是出于兼容性的考虑。(至于向下兼容是一件好事还是坏事,请保持见仁见智的态度。)这就是为什么用来判断一个窗口是否最小化的方法名延续了 IsIconic 的称呼:当用户尝试复原最小化的程序时,程序获得信息仍然叫 WM_QUERYOPEN,而 OpenIcon 方法仍然可以用来『打开』一个最小化的『图标』,尽管保留了上述这些特性的同时,最小化的窗口已经跟图标的长相大相径庭将近十年了。

The OpenIcon function is just an old-fashioned way of saying ShowWindow(hwnd, SW_NORMAL), in the same way that the CloseWindow function (dating back to Windows 1.0) is an extremely old-fashioned way of saying ShowWindow(hwnd, SW_MINIMIZE).

OpenIcon 方法不过是 ShowWindow(hwnd, SW_NORMAL) 的一种旧式叫法,与此相同的还有 CloseWindow(可以追溯到 Windows 1.0)也只是 ShowWindow(hwnd, SW_MINIMIZE) 相对应的超级老的一种叫法而已。

TONT 36513 为什么 DS_SHELLFONT = DS_FIXEDSYS | DS_SETFONT?

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

You may have noticed that the numerical value of the DS_SHELLFONT flag is equal to DS_FIXEDSYS | DS_SETFONT.

你可能曾注意到 DS_SHELLFONT 这个 flag 的数字值是与 DS_FIXEDSYS | DS_SETFONT 相同的。

#define DS_SETFONT 0x40L /* 用于对话框控件的用户指定字体 */

#define DS_FIXEDSYS 0x0008L

#define DS_SHELLFONT (DS_SETFONT | DS_FIXEDSYS)

Surely that isn’t a coincidence.

这当然不是巧合。

The value of the DS_SHELLFONT flag was chosen so that older operating systems (Windows 95, 98, NT 4) would accept the flag while nevertheless ignoring it.

DS_SHELLFONT 这个 flag 的值这样设计,是为了让旧版操作系统(Windows 95、98、NT 4)可以接受这个值的同时忽略它。

This allowed people to write a single program that got the “Windows 2000” look when running on Windows 2000 and got the “classic” look when running on older systems. (If you make people have to write two versions of their program, one that runs on all systems and one that runs only on the newer system and looks slightly cooler, they will usually not bother writing the second one.)

这样的设计,使得人们可以在编写程序时,一次性做到程序在 Windows 2000 下运行时获得『Windows 2000 样式』的同时,在旧版系统上运行时获得『经典样式』。(如果你非要人们编写两个版本的程序,一个可以在所有版本的系统上运行,但另一个只是在新版系统上运行时看上去漂亮一些的话,估计人们根本就不会考虑去写后一个版本。)

The DS_FIXEDSYS flag met these conditions. Older systems accepted the flag since it was indeed a valid flag, but they also ignored it because the DS_SETFONT flag takes precedence.

DS_FIXEDSYS 这个 flag 就可以同时适应这两种情况。旧版系统可以接受这个值,因为它的确是个有效的 flag,但同时也会忽略它,因为 DS_SETFONT 这个 flag 会被优先使用。

This is one of those backwards-compatibility exercises: How do you design something so that it is possible to write one program that gets the new features on new systems while at the same time degrading gracefully on old systems?

这就是向下兼容措施的其中之一:如何设计一种机制,使得只需撰写一个版本的程序,便可以在新系统上获得新功能,同时又在旧系统上可以优雅地降级呢?

TONT 36543 Windows PowerToys 的故事

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

During the development of Windows 95, as with the development of any project, the people working on the project write side programs to test the features they are adding or to prototype a feature. After Windows 95 shipped, some of those programs were collected into the first edition of the Windows 95 Power Toys.

在 Windows 95 的开发过程中,与其他的项目一样,开发人员总会编写一些小工具,用来测试讲要加入的功能,或者为某个功能打造原型。Windows 95 发布之后,其中一些小工具被收录进了第一版的 Windows 95 PowerToys。

As I recall, the first edition contained the following toys:

根据我的回忆,第一版 PowerToys 里有以下这些玩具:

CabView

This was a handy internal tool which also served as a test of the shell folder design.

一个很有帮助的内部工具,同时也是对系统外壳文件夹设计的测试。

CDAutoPlay, DeskMenu, FlexiCD, QuickRes

These were side toys originally written by shell developers for their own personal use.

这些是系统外壳开发人员写来自用的小工具。

Command Prompt Here, Explore From Here(从此处打开命令提示符、从此处打开资源管理器)

These were proof-of-concept toys which tested the shell command extension design.

这些是对系统外壳命令扩展设计的概念论证。

Round Clock(圆形钟)

This was a program to test regional windows.

这是用来测试区域化窗口的程序。

Shortcut Target Menu

This was a feature idea that didn’t quite make it.

这是一个新功能的点子,不过没能实现。

I wasn’t around when the decision was made to package these toys up and ship them, so I don’t know what the rule was for deciding what was PowerToy-worthy and what wasn’t. Nor do I know where the name PowerToy came from. (Probably somebody just made it up because it sounded neat.)

以上这些工具打包发布的时候我并没有参与,所以我也不知道入选或不入选 PowerToy 的标准是什么,也不知道 PowerToy 这个名字是怎么来的(可能有人觉得这样念起来感觉不错,所以就这么愉快的决定了)。

Upon the enormous success of the PowerToys, a second edition was developed. This time, people knew that they were writing a PowerToy, as opposed to the first edition of the PowerToys which was merely cobbled together from stuff lying around. The second edition of the Windows 95 PowerToys added FindX, Send To X, the Telephony Locator Selector, XMouse, and Tweak UI.
Later, the kernel team released their own set of toys, known as the Windows 95 Kernel Toys. Alas, the original blurb text is not on the Microsoft downloads site, but here’s an archived copy. (In reality, it was I who wrote all of the Kernel Toys, except for the Time Zone Editor, which came from the Windows NT Resource Kit. I also wrote the somewhat whimsical original blurb.)

鉴于 PowerToys 的良好反响,这套工具又有了第二版。这一次,开发者们知道自己是在专门开发 PowerToy,而不是像第一版的 PowerToys 那样仅仅是将散落在各处的东西拼凑在一起。Windows 95 PowerToys 第二版增加了 FindX、Send To X(发送到X)、the Telephony Locator Selector(电话位置选择器,用于修改 Windows 95 模拟电话拨号的『所在位置』设置——译注)、XMouse,以及 Tweak UI。后来,内核开发组发布了他们自己的套件,并起名为 Windows 95 Kernel Toys。不巧的是,原始的那些絮絮叨叨的介绍文字已经不在微软的下载站上了,不过这里有一份备份。(实际上,除了时区编辑器之外,是我撰写了所有的 Kernel Toys,而时区编辑器是从 Windows NT Resource Kit 中拿来的。那个冗长而古怪的介绍文字也是我的作品。)

This was all back in the day when it was easy to put up something for download. No digital signatures, no virus checking, no paperwork. Just throw it up there and watch what happens. Today, things are very different. Putting something up for download is a complicated process with forms to fill out in triplicate and dark rooms with card readers. I wouldn’t be surprised if an abandoned salt mine in Montana were somehow involved.

那是个将什么东西发布出来供人下载十分简单易行的年代。没有什么数字签名,没有什么病毒检测,也没有什么文件要签署,只要把它传上去,就可以观察会发生什么化学反应了。现如今,事情已经变得完全不同,要把什么东西发出来供人下载变成了一个复杂的过程,要填一大堆一式三份的表格,还得在带着门禁卡的小黑屋之类的地方。这个过程中就算包含了蒙大拿废弃的盐矿我也不会觉得奇怪。(译注:这句没看懂,如有知道的读者请帮忙解释一下。)

Nowadays, every team at Microsoft seems to have their own PowerToys, trading on the good name of the Windows shell team who invented the whole PowerToys idea. (As far as I can tell, we don’t get any royalties from other divisions calling their toys “PowerToys”.) A quick check reveals the following PowerToys available for download from Microsoft; I may have missed some.

现在,每个微软的团队似乎都有自己的 PowerToys 套件了,这些套件也利用了发明了 PowerToys  这个主意的 Windows 系统外壳团队的名声。(据我所知,其他团队把他们的套件叫做 PowerToys 的时候,我们可一分钱版税都没收到。)快速地浏览一遍让我列出了可以从微软网站上下载到的 PowerToys,或许也有些遗漏了。

  • Microsoft PowerToys for Windows XP Tablet PC Edition [link fixed 11am]
  • PowerToys for the Pocket PC
  • PowerToys Fun Pack
  • PowerToys for Microsoft Office OneNote 2003
  • Microsoft PowerToys for Windows XP Media Center Edition 2004
  • PowerToys for Windows Media Player for Windows XP
  • Windows XP Creativity Fun Pack PowerToys Wallpaper Changer

(译注:以上原文链接已全部失效,故未再做链接,有兴趣可以去看原文)

(Plus, of course, the Windows XP PowerToys, which does come from the shell team. The Internet Explorer team originally called their stuff PowerToys, but they later changed the name to Web Accessories, perhaps to avoid the very confusion I’m discussing here.)

(另外,当然还应该算上 Windows XP PowerToys,也的确是由(Windows)系统外壳团队开发的。Internet Explorer 团队原本也把他们的套件叫做 PowerToys,不过后来改名叫 Web Accessories(网络附件)了,可能就是为了避免这里所说的混乱局面。)

What’s frustrating is that since they are all called “PowerToys”, questions about them tend to go to the shell team, since we are the ones who invented PowerToys. We frequently have to reply, “Oh, no, you’re having a problem with the XYZ PowerToys, not the classic Windows PowerToys. We’re the folks who do the classic Windows PowerToys.”

令人沮丧的是,因为这些套件都叫 PowerToys,有关各种(不同团队的)套件的问题常常会跑到系统外壳团队那里去,毕竟我们是发明了 PowerToys 的人。我们常常需要回复说,『哦,不是的,你的问题与 XYZ PowerToys 有关,而不是传统的 Windows PowerToys,我们是制作传统的 Windows PowerToys 的那批人。』

Even the blog name “PowerToys” has been co-opted by the Visual Studio team to promote their Powertoys for Visual Studio 2003.

甚至连『PowerToys』这个博客名称都被 Visual Studio 团队指派用来宣传 Visual Studio 2003 的 PowerToys 了。

Some people claim that Tweak UI was written because Microsoft got tired of responding to customer complaints. I don’t know where they got that from. Tweak UI was written because I felt like writing it.

有些人声称开发 Tweak UI 的原因是微软已经受够了回复客户的抱怨,我是不知道他们是从哪听来这种说法的。我写 Tweak UI 只是因为我想这么做而已。

That page also says that sometimes PowerToys vanish without warning. That’s true. A few years ago, all the Windows XP PowerToys were taken down so they could be given a security review. Some of them didn’t survive and didn’t come back. Other times, a PowerToy will be pulled because a serious bug was found. Since PowerToys are spare-time projects, it can take a very long time for a bug to get fixed, tested, and re-published. For example, the HTML Slide Show Wizard was pulled after a (somewhat obscure) data-loss bug was found. Fixing the bug itself took just a few days, but testing and filling out all the associated paperwork took six months.

同一篇文章里(译注:即上文中提到 Tweak UI 是微软懒得再回复客户问题的那篇博文,因原文链接已失效,未予链接)还提到有些 PowerToys 套件在未予告知的情况下就消失了,的确有这么回事。几年前,整个 Windows XP PowerToys 都下线了,以便接受安全评估,后来套件中的一些通过了评估,另一些则再也没能回来。其它场合下,某个 PowerToys 套件被撤下是因为发现了严重的 bug。由于 PowerToys 都是在空余时间制作的作品,可能需要很长的时间才能修复 bug、通过测试,然后重新上线。例如,一个叫 HTML 幻灯片向导的组件曾被撤了下来,因为其中发现了一个(隐藏得比较深的)数据丢失漏洞。修好 bug只花了几天时间,但跑测试和填写相关的文书则花了六个月。

There’s no moral to this story. Just a quick history lesson.

上面的故事没有什么寓意,只是讲点小历史而已。

TONT 36673 保持错误代码向下兼容的重要性

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

I remember a bug report that came on in an old MS-DOS program (from a company that is still in business so don’t ask me to identify them) that attempted to open the file “”. That’s the file with no name.

我记得有一个bug报告,是关于一个老旧的 MS-DOS 程序(开发这个程序的公司目前仍在存续中,所以不要问我具体是哪家公司)尝试打开文件“”,也就是一个没有名字的文件。

This returned error 2 (file not found). But the program didn’t check the error code and though that 2 was the file handle. It then began writing data to handle 2, which ended up going to the screen because handle 2 is the standard error handle, which by default goes to the screen.

这样做会使系统报告错误代码2(文件未找到),但程序没有检查错误代码,以为2就是文件句柄,然后就会开始向句柄2填充数据,而数据会显示在屏幕上,而这是因为句柄2是标准错误输出句柄,其默认行为就是输出到屏幕上。

It so happened that this program wanted to print the message to the screen anyway.

碰巧这个程序要做的就是向屏幕输出消息。

In other words, this program worked completely by accident.

换句话说,这个程序只是撞了大运正常工作了。

Due to various changes to the installable file system in Windows 95, the error code for attempting to open the null file changed from 2 (file not found) to 3 (path not found) as a side-effect.
Watch what happens.

在 Windows 95 可以安装在其上的文件系统设计的几次变动中,其中一个副作用是:尝试打开一个不存在的文件回报的错误代码从2(文件不存在)变成了3(找不到路径)。现在来看看会发生什么事。

The program tries to open the file “”. Now it gets error 3 back. It mistakenly treats the 3 as a file handle and writes to it.

程序尝试打开文件“”(空文件名)。现在它获得了错误代码3。程序照旧误打误撞将3作为文件句柄,并开始向其中写入数据。

What is handle 3?

那么句柄3是什么呢?

The standard MS-DOS file handles are as follows:

标准的 MS-DOS 文件句柄如下所示:

句柄 名称 含义
0 stdin 标准输入设备
1 stdout 标准输出设备
2 stderr 标准错误输出
3 stdaux 标准辅助设备(串口)
4 stdprn 标准打印机

What happens when the program writes to handle 3?

当程序尝试向句柄3写入时会发生什么呢?

It tries to write to the serial port.

会尝试向串口写数据。

Most computers don’t have anything hooked up to the serial port. The write hangs.

大多数计算机的串口上什么也没连,所以写操作挂起了。

Result: Dead program.

结果就是:程序死掉了。

The file system folks had to tweak their parameter validation so they returned error 2 in this case.

文件系统开发组对参数校验做了些调整,使其在这种情况下返回错误代码2(来解决这个问题)。