July, 2006

  • The Old New Thing

    Glass houses are great places to throw stones


    Whenever I write an article explaining that programs should avoid doing X, I can confidently rely on a comment saying, "Well, Microsoft Product Q does this!" as if to say, "Gotcha, you hypocrite!"

    But they're saying "gotcha" to the wrong person. Because, and I'm sure it's a shock to many people to read this, I did not personally write every line of software Microsoft ever produced. (And even if I did write it, I may have written it as a younger developer, before I learned about said rule. Because, and I'm sure this is also a shock to many people, I was once a beginner, too.)

    If you find a Microsoft product breaking a rule, then go complain to that product team. Complaining to me won't accomplish anything. I don't have access to their source code, and even if I did, I certainly don't have permission to go in and make changes to their code, nor do I have the time to go in and learn how their product works and figure out the right place to make the fix. Furthermore, and I don't know if you all can handle three shocking revelations in one article, product teams do not send me every line of code for review.

    Indeed, one of the reasons I write here about things programs should or shouldn't do is because I myself will see a Microsoft product breaking a rule! By discussing the problem here rather than in an internal mailing list, the information gets out to everybody. And maybe, just maybe, the product team will read the entry and say, "Oops, I think we do that." Because (shocking revelation number four) not all Microsoft programmers are seasoned experts in Win32 user-interface programming.

    (Articles where I was consciously tapping my colleagues on the head include my discussion of CallMsgFilter, the long and sad story of the Shell Folders key, and reminding you to pass unhandled messages to DefWindowProc. In fact, for every "do/don't do this" article, I'd say odds are good that with enough searching, you can find a Microsoft product that breaks the rule. And when you do, complain to that product team. Even the difference between the tray and the notification area was in part a response to all the other groups that perpetuate the misuse of the terminology.)

    So when I write something like, "Applications shouldn't do this", go ahead and insert the phrase "and this means all applications, including those published by Microsoft." When I write, "some annoying programs", go ahead and insert the phrase, "which might even include programs published by Microsoft". I'm not going to insert those phrases into every sentence I write. I'm assuming you're smart enough to realize that general statements apply to everyone regardless of who signs their paychecks.

    Of course, if the consensus of my readership is that I shouldn't tell you not to do things until every last Microsoft product has been scoured to ensure that none of them violate that rule either, then I can abide by that decision. I'll just stop posting those tips here and keep them on the internal mailing lists. It's much less work for me.

  • The Old New Thing

    Not everybody with a non-Windows partition type is a geek


    In the discussions following why Windows setup lays down a new boot sector, some commenters suggested that Windows setup could detect the presence of a non-Windows partition as a sign that the machine onto which the operating system is being installed belongs to a geek. In that way, the typical consumer would be spared from having to deal with a confusing geeky dialog box that they don't know how to answer.

    The problem with this plan is that not everybody with a non-Windows partition type is necessarily a geek. Many OEM machines ship with a hard drive split into two partitions, one formatted for Windows and the second a small non-Windows partition to be used during system diagnostics and recovery. The presence of this small non-Windows partition is typically not well-known, and it comes into play only when you boot from the manufacturer's "system recovery CD".

    The upshot of this is that if Windows setup took the "anybody with a non-Windows partition must be a geek" approach, it would end up tagging an awful lot of people as geeks who really aren't.

    Now, you might say, "Well, only geeks install the operating system anyway. Normal people typically buy a computer with the operating system pre-installed. The fact that they are running Windows setup proves that they're a geek in the first place. Therefore, Windows setup should be optimized for geeks." Indeed, the premise of this argument—that only geeks run Windows setup—is true, but only once you've reached steady state. In the months immediately following the release of a new version of Windows, everybody is installing the operating system, geeks and non-geeks alike. (There is also an influx of non-geek people installing Windows every Christmas.) Magazine reviewers are writing boatloads of articles on the new operating system, and the initial setup experience is the very first thing they notice about Windows. It had better be smooth and painless.

  • The Old New Thing

    Just because I don't write about .NET doesn't mean that I don't like it


    Some people have inferred that I don't write about .NET because I don't like it. That's not true. I use it myself.

    The reason I don't write about .NET is because I'm not an expert on it and there are plenty of other .NET blogs out there, written by people who are actual experts. (Such as Maoni Stephens, whose little finger contains more knowledge about garbage collection than most people have in their entire brain.) No point adding to it with my non-expert view. Indeed, when I hit upon an interesting .NET topic or puzzle, I usually just forward it off to Brad for him to put on his blog. Because people looking for interesting .NET content go to Brad, not me.

    The fact that Rico Mariani was able to do a literal translation of the original C++ version into C# and blow the socks off it is a testament to the power and performance of managed code. It took me several days of painful optimization to catch up, including one optimization that introduced a bug, and then Rico simply had to do a little tweaking with one hand tied behind his back to regain the lead. Sure, I eventually won but look at the cost of that victory.

    (I'm told there's one company that has decided against using managed code because "If Raymond doesn't even want to mention the .NET Framework then why should we bother to look at it?" What a strange argument. I don't mention IPsec; does that mean you shouldn't use it either?)

    But just to dispel the rumor (and to buck both my title and my tag line), I'm going to declare this week to be .NET week. All my technical articles this week will be about .NET. Enjoy it while you can.

  • The Old New Thing

    Retail companies allegedly not collecting personal information as aggressively


    Several months ago, The Washington Post reported that retail companies were no longer collecting personal information as aggressively. The poster child for this sort of thing was RadioShack, which demanded your name and address even if you just stopped in to buy a pack of AA batteries. I didn't shop there often, and when I did, I merely refused to give them any information about myself. At the store near Microsoft main campus, after going through this exercise, the cashier eventually entered my name as "Cash" and out came the receipt:

    James Cash
    123 Main St
    Redmond, WA 98052

    Thank You, James Cash, for shopping at RadioShack

    I enjoyed telling this story, and to my surprise, one day I got a piece of email from James Cash himself! (As it turns out, one of my friends actually knew James Cash.)

    The story is even funnier: For years, my pet peeve was the way that RadioShack wanted my address - and I refused to give it. There was quite a scene a couple of times, with a salesclerk begging me to give it, and me refusing. Once or twice I had to walk out of the store rather than give the info. However, one time I had a roommate who also didn't want to give out his name and address. His solution? To give my name and address! So that is how my name wound up at that RadioShack...
  • The Old New Thing

    Is the maximum size of the environment 32K or 64K?


    There appears to be some confusion over whether the maximum size of the environment is 32K or 64K. Which is it?


    The limit is 32,767 Unicode characters, which equals 65,534 bytes. Call it 32K or 64K as you wish, but make sure you include the units in your statement if it isn't clear from context.

  • The Old New Thing

    If you know German, the world is, well, slightly more confusing


    While it may be true that if you know Swedish, the world is funnier, I have to admit that my knowledge of German only served to create momentary confusion.

    When I saw the headline that the head of BetonSports was arrested, I thought to myself, "Who the heck would have a web site devoted to sports in concrete?" That's because the German word Beton means "concrete" (the construction material) in English, and the German word Sport means the same as in English.

    It took me a few moments to realize that the company's name is "Bet on Sports".

  • The Old New Thing

    How are DLL functions exported in 32-bit Windows?


    The designers of 32-bit Windows didn't have to worry quite so much about squeezing everything into 256KB of memory. Since modules in Win32 are based on demand-paging, all you have to do is map the entire image into memory and then run around accessing the parts you need. There is no distinction between resident and non-resident names; the names of exported functions are just stored in the image, with a pointer (well, a relative virtual address) to the name stored in the export table.

    Unlike the 16-bit ordinal export table, the 32-bit ordinal export table is not sparse. If your DLL exports two functions, one as ordinal 10 and one as ordinal 1000, you will have a 991-entry table that consists of two actual function pointers and a lot of zeros. Thus, you should try not to have large gaps in your ordinal exports, or you will be wasting space in your DLL's export table.

    As I noted above, there is only one exported names table, so you don't have to distinguish between resident and non-resident names. The exported names table functions in the same manner as the exported names table in 16-bit Windows, mapping names to ordinals. Unlike the 16-bit named export tables, where order is irrelevant, the exported names table in 32-bit Windows is kept sorted so that a more efficient binary search can be used to locate functions.

    As with 16-bit Windows, every named function is assigned an ordinal. If the programmer didn't assign one in the module definition file, the linker will make one up for you, and as with 16-bit Windows, the value the linker makes up can vary from build to build. However, there is a major difference between the two models: Recall that named exports in 16-bit Windows were discouraged (on efficiency grounds), and as a result, every exported function was explicitly assigned an ordinal, which was the preferred way of linking to the function. On the other hand, named exports in 32-bit Windows are the norm, with no explicit ordinal assignment. This means that the ordinal for a named export is not fixed. For example, let's look at the ordinal that got assigned to the kernel32 function LocalAlloc in the early years:

    Windows NT 3.1314
    Windows NT 3.5372
    Windows 95501
    Windows NT 4.0407

    Now, some people are in the habit of reverse-engineering import libraries, probably because they can't be bothered to download the Platform SDK and get the real import libraries. The problem with generating the import library manually is that you can't tell whether the ordinal that was assigned to, say, the LoadLibrary function was assigned by the module definition file (and therefore will not change from build to build) or was just auto-generated by the linker (in which case the ordinal will change). The import library generation tools could just play it safe and use the named export, since that will work in both cases, but for some reason, they use the ordinal export instead. (This is probably a leftover from 16-bit Windows, where ordinals were preferred over names, as we saw earlier.)

    This unfortunate choice on the part of the import library generation tools to live dangerously has created compatibility problems for the DirectX team. (I don't know why DirectX got hit by this harder than other teams. Perhaps because game developers don't have the time to learn the fine details of Win32; they just want to write their game.) Since they used one of these tools, they ended up linking to DirectX functions like DirectDrawCreate by ordinal rather than by name, and then when the next version of DirectX came out and the name was assigned a different ordinal by the linker, their programs crashed pretty badly. The DirectX team had to go back to the old DLLs, write down all the ordinals that the linker randomly assigned, and explicitly assign those ordinals in the module definition files so they wouldn't move around in the future.

    There are other reasons why you cannot generate an import library from a DLL; I'll pick up those topics later when I talk about import libraries in more detail.

    Next time, forwarders.

  • The Old New Thing

    The Seattle Monorail has two trains, and they collided


    Murphy's Law vindicated again. The Seattle Monorail has two trains, and last year they managed to collide. To get this to happen was particularly tricky, since the trains run on separate tracks, and there is only one spot on the entire line where a collision could occur—and they found it. You can read about it in this Associated Press article that describes the monorail as a "mile-high, 43-year-old elevated line". Wow, a mile high. Those must've been really long ladders to get people down.

    It was supposed to resume operation a few weeks ago, but the reopening was delayed due to a glitch in the emergency-braking system. We can't get anything right around here.

  • The Old New Thing

    How do you use the bike rack on a Metro bus?


    While it's true that I often ride the bus and often ride my bicycle, I do not often ride my bicycle onto a bus. This means that I forget how it's done and have to refresh my memory. Fortunately, Arlington Transit uses the same bike rack design as we do here in Metro King County, so I can refer to their detailed pictures instead of our diagrams which leave a bit to be desired.

    It's not that hard, really. There are instructions on the rack itself for most of the steps. You squeeze the handle where it says "pull here", lower the rack, place the front tire where it says "front tire", the back tire where it says "back tire", and put the support arm into place.

    Two details are omitted from the instruction on the rack: First, if you're the first bicycle on the rack, use the slot furthest away from the bus. And second, how do you use that support arm?

    I'm always baffled by the support arm. It won't fit over the tire! Oh, wait, because it's on a spring. You have to pull outwards in order extend the clamp. Then it will fit over your tire, and then you let it retract and hold the tire in place.

    Metro has other tips on how to prepare your bicycle and the protocol to follow with the bus driver. One bus driver mentioned that the rack was designed by "some guy in Bellevue, or maybe Kirkland". Following up on this information led me to bike rack trivia: The racks are manufactured by Sportworks in the nearby town of Woodinville. Here's the Sportworks version of the story.

    (And another Metro Transit tip: If you want a series of options clustered around a particular time, you can use the commuter trip planner, handy if you don't know exactly what time you will be returning. There's also the point to point schedule maker if you want a custom bus schedule between two stops. And no discussion of Metro Transit planning tools is complete without a plug for Bus Monster.)

  • The Old New Thing

    Names in the import library are decorated for a reason


    When I wrote that the symbolic name for the imported function table entry for a function is called __imp__FunctionName, the statement was "true enough" for the discussion at hand, but the reality is messier, and the reason for the messy reality is function name decoration.

    When a naive compiler generates a reference to a function, the reference is decorated in a manner consistent with its architecture, language, and calling convention. (Some time ago, I discussed some of the decorations you'll see on x86 systems.) For example, a naive call to the GetVersion function results in the compiler generating code equivalent to call _GetVersion@0 (on an x86 system; other architectures decorate differently). The import library therefore must have an entry for the symbol _GetVersion@0 in order for the external reference to be resolved.

    To correspond to the stub function whose real name is _GetVersion@0 is the import table entry whose name is __imp__GetVersion@0. In general, the import table entry name is __imp_ prefixed to the decorated function name.

    The fact that names in import libraries are decorated means that it is doubly crucial that you use the official import library for the DLL you wish to use rather than trying to manufacture one with an import library generation tool. As we noted earlier, the tool won't know whether the ordinal assigned to a named function was by design or merely coincidental. But what's more, the tool won't know what decorations to apply to the function (if the name was exported under an undecorated name). Consequently, your attempts to call the function will fail to link since the decorations will most likely not match up.

    In that parenthetical, I mentioned exporting under undecorated names. Doesn't that mean that you can also export with a decorated name? Yes you can, but as I described earlier, you probably shouldn't. For as I noted there, if you export a decorated name, then that name cannot be located via GetProcAddress unless you also pass the decorated name to GetProcAddress. But the decoration schema changes from language to language, from architecture to architecture, and even from compiler vendor to compiler vendor, so even if you manage to pass a decorated name to the GetProcAddress function, you'll have to wrap it inside a huge number of #ifdefs so you pass the correct name for the x86 or ia64 or x64, accordingly, as well as changing the name depending on whether you're using the Microsoft C compiler, the Borland C compiler, the Watcom C compiler, or maybe you're using one of the C++ compilers. And woe unto you if you hope to call the function from Visual Basic or C# or some other language that provides interop facilities.

    Just export those names undecorated. Your future customers will thank you.

    (Exercise: Why is it okay for the C runtime DLLs to use decorated exports?)

Page 1 of 4 (39 items) 1234