April, 2006

  • The Old New Thing

    Grace period for Swedish currency conversion extended to the end of the year


    Like the United States, Sweden is in the process of upgrading their paper currency to incorporate new security measures. Unlike the United States, Sweden is declaring the old bills no longer valid. The original plan was that the old 20-kronor, 100-kronor and 500-kronor notes would expire today, but due to the enormous number of outstanding old bills (1.5 billion kronor, by Riksbanken's estimation), the grace period for turning in your old notes has been extended to the end of the year.

    The expiration date for the silver 50-öre coin has not changed, however. Today is still the last day those coins are legal tender. I think I have a 50-öre coin or two in my "leftover Swedish money" collection. Sure, it was a souvenir, but now it's officially one. (50 öre is approximately US$0.07.)

    When the United States updates its currency, it does not declare the old currency invalid. Partly this is an acknowledgement of the sensibilities of its citizens, especially the people who don't trust banks and keep piles of cash hidden in their house. But it's also an acknowledgement that most United States paper money isn't even in the United States. The United States dollar has historically been the stable currency of choice (though the Euro appears to be poised to overtake the dollar soon), and you can probably still find mattresses stuffed with $100 bills in some countries.

  • The Old New Thing

    What does CS_SAVEBITS do?


    If you specify the CS_SAVEBITS class style, then the window manager will try to save the bits covered by the window. But the real question is why, because that is your guide to using this power only for good, not for evil.

    When a window whose class specifies the CS_SAVEBITS class style is displayed, the window manager takes a snapshot of the pixels on the screen where the window will be displayed. First, it asks the video card to store the pixels in available off-screen video memory (fast). If no video memory is available, then the pixels will be stored in system memory (slower). If the saved pixels have not been discarded in the meantime (see below), then when the window is hidden, the saved pixels are copied back to the screen and validated; in other words, the pixels are marked as "good" and no WM_PAINT message is generated.

    What invalidates the saved pixels? Anything that would cause those pixels to be out of sync with what should be on the screen once the popup window is removed. Here are some examples:

    • If the popup window moves, then the saved pixels are discarded, since putting those pixels back on the screen would put them in the wrong place.
    • If an underlying window invalidates itself (most commonly via InvalidateRect), then the saved pixels are also discarded, because the underlying window has indicated that it wants to change its pixels.
    • If any windows beneath the popup change size or position or z-order, then the saved pixels are of no use.
    • If any windows are created or destroyed beneath the popup.
    • If somebody calls GetDC for a window beneath the popup and starts drawing.

    You get the idea. If copying the saved pixels back to the screen would result in an inconsistent display, then the saved pixels are discarded.

    So how do you use this power for good and not for evil?

    One consideration is that the region should cover a relatively small portion of the screen, because the larger the saved bitmap, the less likely it will fit into available off-screen video memory, which means the more likely it will have to travel across the bus in a video-to-system-memory blit, the dreaded "vid-sys blt" that game developers are well familiar with. In the grand scheme of vid/sys blts, "vid-vid" is the fastest (since the video card is very good at shuffling memory around within itself), "sys-sys" is next best (since the motherboard can shuffle memory around within itself, though it'll cost you CPU cache space), "sys-vid" is in third place, and "vid-sys" is the worst: Programs write to video memory much more often than they read from it. As a result, the bandwidth between the video card and system memory is optimized for writing to video, not reading from it.

    But the primary concern for deciding when to use the CS_SAVEBITS window class style is not making the window manager go to all the trouble of saving the pixels, only to have to throw them away. A window that is a good candidate for the CS_SAVEBITS style is therefore one that does not move, covers a relatively small portion of the screen, and is visible for only a short time. That the window shouldn't move is obvious: If the window moves, then the saved pixels are useless. The other two rules of thumb try to minimize the opportunity for another window to do something that invalidates the saved pixels. By keeping the window small in area and putting it on the screen for only a short time, you keep the "target" small both spatially and temporally.

    Consequently, the best candidates for CS_SAVEBITS are menus, tooltips, and small dialogs, since they aren't too big, they don't typically move around, and they go away pretty quickly.

    (Some people appear to be under the mistaken impression that CS_SAVEBITS saves the bits of the window itself. I don't know where people get this impression from since even a modicum of experimentation easily demonstrates it to be false. The Windows drawing model follows the principle of Don't save anything you can recalculate.)

  • The Old New Thing

    A new scripting language doesn't solve everything


    Yes, there are plenty of scripting languages that are much better than boring old batch. Batch files were definitely a huge improvement over SUBMIT back in 1981, but they've been showing their age for quite some time. The advanced age of boring old batch, on the other hand, means that you have millions of batch files out there that you had better not break if you know what's good for you. (Sure, in retrospect, you might decide to call the batch language a design mistake, but remember that it had to run in 64KB of memory on a 4.77MHz machine while still remaining compatible in spirit with CP/M.)

    Shipping a new command shell doesn't solve everything either. For one thing, you have to decide if you are going to support classic batch files or not. Maybe you decide that you won't and prefer to force people to rewrite all their batch files into your new language. Good luck on that.

    On the other hand, if you decide that you will support batch files after all, then presumably your new command shell will not execute old batch files natively, but rather will defer to CMD.EXE. And there's your problem: You see, batch files have the ability to modify environment variables and have the changes persist beyond the end of the batch file. Try it:

    C> copy con marco.cmd
    @set MARCO=polo
            1 file(s) copied.
    C> echo %MARCO%
    C> marco
    C> echo %MARCO%

    If your new command shell defers to CMD.EXE, these environment changes won't propagate back to your command shell since the batch file modifies the environment variables of CMD.EXE, not your shell. Many organizations have a system of batch files that rely on the ability to pass parameters between scripts by stashing them into environment variables. The DDK's own razzle does this, for example, in order to establish a consistent build environment and pass information to build.exe about what kind of build you're making. And I bet you have a batch file or two that sets your PROMPT or PATH environment variable or changes your current directory.

    So good luck with your replacement command shell. I hope you figure out how to run batch files.

  • The Old New Thing

    No good deed goes unpunished: Bug assignment


    Sometimes you're better off keeping your fool mouth shut.

    The other day I got a piece of email requesting that I look at a crashed system because the tester believed it was another instance of bug 12345. While that may very well have been the case, bug 12345 was a kernel pool corruption bug in the object manager, something of which I know next to nothing.

    Why was I being asked to look at the machine? Because the bug was originally assigned to my team. As a gesture of good will, I reassigned the bug to a more appropriate team, and that was my downfall, because that put my fingerprint on the bug report. The second occurence of the bug was inside another component entirely, still completely unrelated to my team. But the tester thinks that I am somehow responsible for fixing the bug since my name is now in the bug report.

    Perhaps I need an alter ego whose name I can use for cases like this, where my involvement in a bug is not as an interested party, but rather as somebody merely offering to help redirect the bug to the correct developer. But that merely defers the problem: What should I do if somebody asks the alter ego to investigate the bug?

  • The Old New Thing

    Correctly spell xerophthalmia and the crowd goes wild


    One of the things I did in San Francisco was attend a performance of The 25th Annual Putnam County Spelling Bee. I went into the show with some trepidation, fearing that it would recall painful memories from my own career on the spelling bee circuit as a middle-schooler. Fortunately, my experience as a spelling bee participant only served to make the show more enjoyable.

    Each performance is different because four volunteers from the audience are invited to join the six student characters on the stage to participate in the bee. Things got off to an unexpected start when the first audience member misspelled "Mexican", which threw the script for a minor loop since one of the characters complains later about that "easy" word. A second audience member dropped out shortly thereafter, but the last two managed to hang on a bit longer. The third eventually dropped out on "dengue".

    The last audience member, on the other hand, kept spelling words correctly. It was obvious that we had reached the point in the script where all audience participants were to be eliminated, because they kept calling him to the microphone for another word. He was doing so well that the cast members had trouble keeping straight faces. The crowd went nuts when he spelled xerophthalmia correctly. (You could tell who the spelling bee veterans in the audience were, because we were the ones who cheered wildly as soon as he finished spelling, before the judge ruled him correct. After all, xerophthalmia is not a difficult word, being a simple combination of the Greek roots xeros, meaning dry, and ophthalmos, meaning eye.) After xerophthalmia, he got the "word" pharmacologicalmum. (Yes, the judge mumbled the end of the "word".) And as soon as he started spelling with "p", the judge eagerly rang the bell and declared "no, it's an f."

    The first half of the show was extremely funny, for it is then we are introduced to each of the (cast member) spellers and their quirky spelling techniques. That's also where the bulk of the spelling takes place, and where we are treated to the wickedly twisted sample sentences, two examples of which can be found in the clip I linked to above. (We also get Olive's sweet My Friend, The Dictionary and the wonderfully out-of-control Pandemonium.) The second half drags a bit, but I Speak Six Languages injects some long-absent freneticism, including a little fourth-wall breakage when Marcy displaces the orchestra pianist and starts playing her own accompaniment!

    If this show ever comes into your area, I wholeheartedly recommend seeing it.

  • The Old New Thing

    No, really, you need to pass all unhandled messages to DefWindowProc


    Earlier I had discussed that you have to return the special value BROADCAST_QUERY_DENY if you want to deny a device removal query because too many programs thought that they had covered "all" the Windows messages and just returned zero for the others. Since then, there have been lots of other window messages added to the system, many of which contain nontrivial processing in DefWindowProc. Yet, every so often, I run into another program that assumed that "Microsoft will never enhance the window manager" and simply returned zero for all the messages they didn't handle.

    Indeed, often these programs don't even cover all the existing messages! One program had a helper window that handled just a few messages and returned zero for the rest. As a result, you couldn't shut down the computer because returning zero in response to the WM_QUERYENDSESSION message means, "No, don't shut down." I guess the people who wrote that program assumed you would shut down their program manually. (Programs are not supposed to fail a shutdown unless the decision came from the user, typically by clicking "Cancel" in response to a "Do you want to exit without saving?") Custom keyboard buttons like the volume control buttons didn't work either (if focus was on this helper window), because it neglected to pass the WM_APPCOMMAND message to the DefWindowProc function.

    Therefore, once again, I implore you: If you don't handle a message in your window procedure, pass it to the DefWindowProc function. Your customer base thanks you.

    (Note for people who take what I say too literally: If you are using a framework, then follow that framework's protocol for indicating that you want default message processing to occur. For example, dialog procedures do not pass unhandled messages to the DefWindowProc function; they merely return FALSE to indicate that default processing should take place.)

  • The Old New Thing

    Ich habe meinen Computer zu Deutsch gewechselt


    This weekend, I changed my computer's user interface language from Swedish (where it had been since November 2003) to German. Germany is the country I'm most likely to vacation to next, and I figured I should start pseudo-immersing myself. Of course, all it really means is that I'm going to be learning a lot of computer-related German words like Einstellungen and Speicher.

    The change will also take additional adjustment because I learned German under the old spelling rules, before the controversial spelling reform of 1996 was promulgated. Perhaps the most prominent change is the new rules for the ß character, but for me personally, that change is barely noticeable because I learned German from a textbook that uses Swiss spelling! (The Swiss do not use the ß character; they use double-s instead.) Learning from a Swiss textbook also means that I learned phrases like "Tschüss" and "Bilder knipsen", my use of which amuses Germans to no end. One of the lesser rules that affects me more is the regularization of rules surrounding noun capitalization, as in "zu Deutsch" above.

    This completes the switch to German that began in January when I changed my Microsoft Office language to German. For the past few months I had been running a mix of Swedish and German. That sounds confusing, but it wasn't that bad, really. I barely even realized that half of my dialog boxes were in one language and half were in another. (Well, okay, and the third half was in English. The programs that are neither part of Windows nor part of Office remain in English.) The real hard part is learning all the new keyboard shortcuts.

    (In marginally related news, the Swedish Academy recently released its latest official Swedish word list, and it changed its longstanding policy and now lists the words beginning with "W" separately from words beginning with "V". Up until now, "W" and "V" had been considered merely typographical variants of one another and had been treated as identical for alphabetization purposes.)

  • The Old New Thing

    Troubleshooting tips are not formal product documentation


    The Microsoft Knowledge Base is filled with product support tips, but be careful to understand the scope of those tips. Generally speaking, information provided in the Knowledge Base exists for troubleshooting purposes, not for program design. That's why each article lists specifically which operating system it applies to: There is no guarantee that a particular tip will work on future operating systems. This is particularly true if the tip recommends digging into a program's internal data structures, persistence formats, or files. The Knowledge Base article is for helping you get yourself out of a mess; it is not formal product documentation. Think of it as a Microsoft version of Experts Exchange. (I always wondered how many people misread that site as "Expert Sex Change".)

    Knowledge Base articles typically come from the product support groups. Someone might solve a problem with a customer's machine and say, "You know, I bet other people will run into this problem, too. Let me document how I fixed it to save time for the next person." They'll write up a Knowledge Base article and add it to the database. Sometimes (rarely, in my experience), they will run the article past the product group responsible for the topic area for a technical review before publishing it. In other words, articles in the Knowledge Base come with a lower "level of service" than formal product documentation; they were not necessarily approved by the product group. If it helps you solve your problem, then great! But there's no promise that it will, and neither is there a promise that the solution will work in the next version of the operating system. It's just a bunch of IT folks sharing war stories.

    The explanation above is also wrong.

    Due to the quick publishing times of the Knowledge Base compared to the formal product documentation, a product group will often take a shortcut and publish their documentation via the Knowledge Base in order to get the information out quicker. As a result, some Knowledge Base articles really are formal product documentation disguised as troubleshooting tips.

    Sometimes a Knowledge Base article does go through product group review, such as the pair of articles describing how to use rundll32 to debug a control panel and how to start a control panel programmatically. The programmatic method is to use the Control.exe program, which has been the supported mechanism since Windows 3.0. The rundll32 technique is only for debugging purposes. If you use the rundll32 technique in your production software, you will run into problems because you're bypassing the official entry point and going for the internal entry point. The official entry point has the compatibility hacks, knowing about the names of control panels that have been retired and redirecting them to their replacements, knowing where shell special folders have moved to, and knowing how to compensate for 64-bit programs trying to run 32-bit control panels and vice versa. But if you go straight to rundll32, you miss out on all this. That's why the article says that the rundll32 method is for debugging purposes, not for production use.

    The bad news for you, poor reader, is that it's not clear from the text of the article which type of article you have. Is it (1) an as-is tip from a product support technician in the hopes you might find it useful, (2) an as-is tip that the product group approved as solution that they will support in the future, or (3) product documentation disguised as a support tip?

    Personally, I can tell the difference between {1,2} and {3} just by the tone of the article and the general sense of "Gosh, I wonder if the product team really expects to be supporting this mechanism in the future." Maybe I was just born with this skill (or perhaps developed it early on in my career as a software developer), because it seems most people can't tell the difference.

    Here's the question to ask: Does the proposed solution rely on what appears to be a side-effect, internal behavior, or internal data structure that a programmer would want to reserve the right to change in the future? Does it feel like a cobbled-together solution? Does it involve duct tape and string?

    I'm sorry it's such a mess, but with hundreds of thousands of Knowledge Base articles in existence, it would be impossible for me to go through and tag each one. You'll have to use your best judgement.

  • The Old New Thing

    Then again, it might not be overclocking after all


    While it's true that there's an awful lot of overclocking out there, it's also true that not everything that looks like overclocking actually is.

    Last Thanksgiving, I helped one of my relatives upgrade their computer by scavenging parts from another unused computer (installing more memory and replacing a broken CD drive). When I took the front panel off the machine, I was greeted with a wall of dust. A little wrangling with a vacuum cleaner was called for before I got around to yanking the broken CD drive and installing the replacement.

    When we go through the failure reports that people submit, we find a lot of single-bit errors, where the correct value and the actual value differ in only one bit position. If these problems are systematic, then that would be the sign of some sort of software problem, but the ones we saw were one-time events, isolated single-bit errors. We had no proof, but we suspected flakey memory, possibly the result of an overheated machine.

    People often stick their computers in out-of-the-way locations, against walls, on a carpeted floor, in a closet. While that's very convenient for home decor, the computer itself suffers because the flow of air through the computer has been impaired. The accumulation of dust impedes the cooling effect further. So make sure the vents on your computer are clean and unobstructed, or you too may find yourself on the short end of a memory glitch caused by overheating.

    Jeremy Kelly from the Exchange Server team was part of the team that investigated a crash that looked just like overclocking, except it wasn't. The program crashed on a mov eax, 0x20 instruction, an instruction that merely loads a constant into a register. It doesn't access memory; it's not a privileged instruction; there's no reason why the instruction could fail. Yet it did.

    This looked like overclocking, but the problem was consistently reproducible (atypical of overclocking), and besides, companies that pay tens of thousands of dollars for an Exchange server system aren't going to skimp on a few hundred by overclocking it. The Exchange server team were fortunate enough to be able to capture a live debug session, which permitted them to investigate the problem both on the user-mode side and on the kernel-mode side, and that revealed the true cause: The Exchange server had been infected with a rootkit.

    The rootkit was lying to the user-mode debugger about what code was executing. It told the debugger that the instruction was the harmless one, when in fact the rootkit was doing something else. Looking at the problem from the kernel-mode side allowed our investigators to identify the true cause of the problem: A crashing bug in the rootkit itself.

  • The Old New Thing

    More about the house in front of Microsoft's RedWest campus


    After I mentioned that house in front of Microsoft's RedWest campus, I received an e-mail message from Mike Daly which corrects some of my mistakes and provides additional details:

    Actually, there were two houses in the strip in front of RedWest. The one you show has not been moved. The other ended up on blocks and parked opposite the RedWest driveway while the parking garage was built. That house eventually was moved north down the street and put on a foundation (about two years ago). You can see it in the middle of this picture. The yard is in straw, and there is a new blacktop drive going down the north side into the backyard.

    After the house was put on the foundation, a sign went up to subdivide the land. As far as I can tell, the house has never been lived in (in the new location). In fact the electricity has not been connected. I've been running past those houses for years, and it has been strange to watch the one move up and down the street. Also, when the land was purchased by Microsoft, there were two old chicken coops in the middle of the property under the largest blackberry brambles you have ever seen.

    I also recommend that you go back to that earlier article, because there's some good info in the comments.

Page 1 of 4 (34 items) 1234