TONT 为什么会有一个单独的 GetSystemDirectory 方法?

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

If the system directory is always %windir%\SYSTEM32, why is there a special function to get it?

如果系统目录总会是 %windir%\SYSTEM32,为什么还有专门的一个方法来获取它?

Because it wasn’t always that.

因为并不总是如此。

For 16-bit programs on Windows NT, the system directory is %windir%\SYSTEM. That’s also the name of the system directory for Windows 95-based systems and all the 16-bit versions of Windows.

对于 Windows NT 下的 16 位应用程序来说,系统目录是 %windir%\SYSTEM。对于以 Windows 95 为基础、以及所有16位版本的 Windows 来说也是如此。

But even in the 16-bit world, if it was always %windir%\SYSTEM, why have a function for it?

然而,即便在16位的世界里,如果系统目录总会是 %windir%\SYSTEM 的话,那为什么还需要专门的一个方法呢?

Because even in the 16-bit world, it wasn’t always %windir%\SYSTEM.

因为即使在16位的世界里,也并不总是如此。

Back in the old days, you could run Windows directly over the network. All the system files were kept on the network server, and only the user’s files were kept on the local machine. What’s more, every single computer on the network used the same system directory on the server. There was only one copy of USER.EXE, for example, which everybody shared.

在过去,你可以直接通过网络来运行Windows。所有的系统文件都存放在网络服务器上,只有用户的文件保存在本地。另外,网络上的所有计算机都会调用服务器上相同的系统目录,例如,只会有一份USER.exe供所有人共享使用。

Under this network-based Windows configuration, the system directory was a directory on a server somewhere (\\server\share\somewhere) and the Windows directory was a directory on the local machine (C:\WINDOWS). Clients did not have write permission into the shared system directory, but they did have permission to write into the Windows directory.

在这种以网络为基础配置的Windows环境下,系统目录是存放在服务器上的某处的(例如\\server\共享名\共享目录),而Windows目录是本机上的某个文件夹(例如C:\WINDOWS)。客户端没有权限写入系统目录,不过的确有权限对Windows目录进行写入。

That’s why GetSystemDirectory is a separate function.

这就是为什么GetSystemDirectory是单独存在的一个方法。

TONT 37903 有时候游戏的 bug 不玩到后期是体现不出来的

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

I didn’t debug it personally, but I know the people who did. During Windows XP development, a bug arrived on a computer game that crashed only after you got to one of the higher levels.

我并不亲自进行调试工作,不过我认识做这项工作的人。在 Windows XP 的开发过程中,曾经有款游戏的一个 bug,只有玩到进度比较深入的时候才会显现,并使游戏崩溃。

After many saved and restored games, the problem was finally identified.

存档读档很多次之后,问题终于定位出来了。

The program does its video work in an offscreen buffer and transfers it to the screen when it’s done. When it draws text with a shadow, it first draws the text in black, offset down one and right one pixel, then draws it again in the foreground color.

游戏的程序在一处屏幕外的缓冲区中处理图像,当处理完成后,再传输到屏幕上。绘制带阴影的文字时,程序会先以黑色将文字绘制一遍,将其向右、向下移动各1个像素,然后再用前景色将文字绘制出来。

So far so good.

到此为止还没什么问题。

Except that it didn’t check whether moving down and right one pixel was going to go beyond the end of the screen buffer.

只是开发商忘了检查向右、向下移动各1个像素的时候,有没有超出屏幕缓冲区的边界。

That’s why it took until one of the higher levels before the bug manifested itself. Not until then did you accomplish a mission whose name contained a lowercase letter with a descender! Shifting the descender down one pixel caused the bottom row of pixels in the character to extend past the video buffer and start corrupting memory.

这就是为什么只有打到高等级的时候 bug 才会显现,因为直到那时才会完成一个任务,而这个任务的名字里有一个带下延部(注1)的小写字母!将这个字母的下延部下移1个像素,会导致底部一行的像素超出视频缓冲区,进而损毁了内存数据。

Once the problem was identified, fixing it was comparatively easy. The application compatibility team has a bag of tricks, and one of them is called “HeapPadAllocation”. This particular compatibility fix adds padding to every heap allocation so that when a program overruns a heap buffer, all that gets corrupted is the padding. Enable that fix for the bad program (specifying the amount of padding necessary, in this case, one row’s worth of pixels), and run through the game again. No crash this time.

找到问题的根源后,修复起来就相对比较容易了。应用程序兼容性团队有一口袋的戏法,其中之一名叫『HeapPadAllocation』。这一兼容性修复补丁会为每个堆分配增加一块补丁,这样当程序发生了堆缓冲区溢出的问题时,弄坏的就只是这块补丁而已。为这个惹事的程序启用这个补丁(指定所需的补丁大小,此处即1行像素的尺寸),再运行游戏,就不会再崩溃了。

What made this interesting to me was that you had to play the game for hours before the bug finally surfaced.

这件事让我感到有趣的一点是,你得把这款游戏先玩上4个小时,然后bug才会崭露头角。


注1:在西文字体排印学中,降部(英语:Descender)指的是一个字体中,字母向下延伸超过基线的笔画部分,也称为下延部。如图所示,字母y第二笔的“尾巴”部分就是降部。另外字母v两条对角线连接的时候也有超过基线的部分,虽然很少,但也是降部。(以上信息来自维基百科『降部』词条

TONT 37983 为什么Windows会将你的BIOS时间设定为本地时间?

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

Even though Windows NT uses UTC internally, the BIOS clock stays on local time. Why is that?

尽管 Windows NT 内部使用 UTC 时间,但 BIOS 的时钟却仍然设定为本地时间,这是为什么呢?

There are a few reasons. One is a chain of backwards compatibility.

原因有几个,其中之一是一系列向下兼容性问题。

In the early days, people often dual-booted between Windows NT and MS-DOS/Windows 3.1. MS-DOS and Windows 3.1 operate on local time, so Windows NT followed suit so that you wouldn’t have to keep changing your clock each time you changed operating systems.

早年间,人们经常在 Windows NT 和 MS-DOS / Windows 3.1 之间双启动。MS-DOS 和 Windows 3.1 使用本地时间,所以 Windows NT 延续了这一设计,以便你每次更换(启动的)操作系统的时候不用总是去修改时间。

As people upgraded from Windows NT to Windows 2000 to Windows XP, this choice of time zone had to be preserved so that people could dual-boot between their previous operating system and the new operating system.

后来人们从 Windows NT 升级到了 Windows 2000 直至 Windows XP,对于时区的设定也需要被保留,以便于人们可以在以前和后来的操作系统间进行双启动。

Another reason for keeping the BIOS clock on local time is to avoid confusing people who set their time via the BIOS itself. If you hit the magic key during the power-on self-test, the BIOS will go into its configuration mode, and one of the things you can configure here is the time. Imagine how confusing it would be if you set the time to 3pm, and then when you started Windows, the clock read 11am.

另一个将 BIOS 时钟设定为本地时间的原因是避免使人们通过 BIOS 设置程序设定时间时产生疑惑。如果在开机自检的时候按下相关的按键,BIOS 会进入设置模式,其中一项可以进行设置的就是当前时间。想象一下如果你把时间设置为下午3点,等进了 Windows 时却发现时间变成了早上11点的感觉。

“Stupid computer. Why did it even ask me to change the time if it’s going to screw it up and make me change it a second time?”

『电脑这玩意简直太蠢了,既然它又会把时间设置搞乱再让我去修改第二次,那从一开始为啥要让我去改呀?』

And if you explain to them, “No, you see, that time was UTC, not local time,” the response is likely to be “What kind of totally propeller-headed nonsense is that? You’re telling me that when the computer asks me what time it is, I have to tell it what time it is in London? (Except during the summer in the northern hemisphere, when I have to tell it what time it is in Reykjavik!?) Why do I have to remember my time zone and manually subtract four hours? Or is it five during the summer? Or maybe I have to add. Why do I even have to think about this? Stupid Microsoft. My watch says three o’clock. I type three o’clock. End of story.”

这时候如果你像这类人去解释:『不是的,那个时间是 UTC 时间,不是本地时间』,很可能会被回击『那又是他喵的什么鬼东西?你是说电脑让我设置时间的时候,我得把伦敦时间给输进去?(除了北半球夏季的时候,那就得输入雷克雅未克的时间了!?)凭什么我得记住我所在的时区,然后手工减去四个小时,或者夏令时的时候得减五个小时?哦,有时候还得用加的,为什么我非得做这些事不可啊?傻×微软,我的手表说现在是三点,我就输入三点,完事。』

(What’s more, some BIOSes have alarm clocks built in, where you can program them to have the computer turn itself on at a particular time. Do you want to have to convert all those times to UTC each time you want to set a wake-up call?)

(更有甚者,有些 BIOS 还有内置的闹钟功能,可以通过设置它来让计算机在特定的时间启动。你会乐意每次设置它之前,手工先将所有的时间转成 UTC 时间吗?)

Day 11477 长颈鹿复制器

  日常工作中,本人遇到一个非常具体的问题:由于日常需要将书籍印刷的文件进行归档处理,而这些文件中,很大一部分是InDesign设计文件的链接图(即印刷文件中调用的图片),而这些链接图的文件名由于编辑和排版人员的习惯问题,常常会遇到文件名超级长的场合,例如:

北京故宫南北长961米,东西宽753米,面积约为725000平方米,四周环以城墙,外围有护城河保护。有四门:正南为午门,东为东华门,西为西华门,北为玄武门(神武门)。现神武门为故宫博物院正门。城墙高9.9米厚8.26米.jpg

  类似这样的文件名,在存在于单层目录中时问题不大,然而归档的时候,由于需要按照日期等建立深层目录,形如:

Z:\排版文件\已定稿印刷\故宫的历史(全12册)\故宫的历史(2020年第1期)\Links

  此时会撞上Windows传统的路径长度260字符限制,以往的处理方式都是将复制时出现这样问题的文件名进行缩短,直至路径长度达到允许值为止,但在某次某本书里有几十个类似情况后,深感崩溃。

  读到这里,急着抬杠的大聪明请先看以下几条,不服的请关掉本窗口,因该工具与您无关:

  1、由于印刷文件后期需要进行导出PDF等操作,必须将排版文件内的图片与实际文件进行链接,故不宜将文件名胡乱修改为1.jpg、2.jpg这样毫无意义的文件名,不然在InDesign中进行重新链接时,就只能根据图像内容人眼识别了(InDesign没有根据图片内容或特征自动重新链接的功能),而这项工作是非常劳累的;

  2、原文件名中可能包含一些排版中没有的信息,如图片的作者姓名等,由于总数据量略多(大约50年左右的数据),实在无暇进行手工数据清洗;

  3、想提通过修改组策略或注册表在Win10下突破260字符路径长度的不必提了:首先目标机器是一台群晖,SMB共享无法突破此限制;其次,即使搞定了我的机器和群晖,还有众多最低使用XP的用户会访问这个资料库,升级系统是不可能的,故最终不要考虑该方式

  4、想让我去跟编辑、排版人员谈谈的可以休矣,我的职权有限,无权干涉别人的工作方式;

  5、想让我换工作的,您给介绍?不给就算了。

  如果到此还没有关掉窗口,请继续阅读。

  本软件的功能很简单,仅仅是调用了C#中最基本的File.Copy进行文件复制,唯对文件名缩短这一流程进行了自动化,即:当遇到文件名过长、导致路径超过260字符限制时,自动将文件名(不含扩展名部分)一个一个字符地进行缩短,直至可以成功复制为止,最大限度保留原文件名。最坏的情况为缩至1个字符仍无法复制,则会复制失败。

  由于该工具只是本人辅助工作的小工具,故可能永远保持目前的单一功能,不会进行更新,但欢迎有相同需要的用户进行试用、并反馈bug。

  本工具不能对长颈鹿进行复制(“长颈鹿”实际是对“长路径”的揶揄)。

  本工具实际与赤蛮奇没有关系(同样只是对“长颈鹿”的揶揄)。

  本工具需要 .Net Framework 4.6.1。

  下载地址

Day 11375 使用群晖作为UPS服务器联动Windows服务器关机

单位之前买了一台群晖DS416作为资料存储器,并在其后追加购置了一台APC BK650-CH的UPS作为掉电保护措施。该型号为后备式,并具备通讯端口,主要用于在市电断开时通知与之相连的设备进行关机,对群晖的硬盘起到保护作用。

后来,在群晖的旁边放置了一台组装的小服务器,运行 Windows Server 2008 R2 处理一些额外的事务。然而,该型号UPS只有一个通讯口,无法由UPS自身同时通知群晖和小服务器进行紧急关机。幸而,群晖支持作为UPS服务器使用,可由其通知其它最多5个设备的UPS客户端进行关机操作,以下为具体的配置过程,及尝试过程中遇到的一些问题的附录。

(更多…)