August, 2008

  • The Old New Thing

    Why was the RAM drive removed from Windows 95?


    Commenter Travis Owens asks, "Why was the RAM drive removed from Windows 95?"

    As with many of these types of accusatory questions, this comes with a false hidden assumption, in this case, that the RAM drive was in Windows 95 to begin with.

    Remember that Windows 95 introduced a new driver model, so any RAM drive would have had to be written from scratch. (Well, okay, you could use the old 16-bit RAM drive, but then you'd be going through the real-mode mapper, at which point your performance would go down the tubes.) As you admitted, it was a very niche feature that usually hurts but can sometimes help in very specific circumstances. Which Windows 95 file system feature would you have cut so that the geeks could have their RAM drive? Should we even be showing RAM drives to typical users, who would just turn it on without understanding its consequences, winding up with a computer that ran worse than if it had never been there?

    If you want a RAM drive, you can sit down with the DDK and write one. But the Windows 95 folks decided that adding support for SCSI hard drives would be a more effective use of the time and skills of the Windows 95 storage device driver development team—which, as I recall, consisted of three people.

    Mind you, if you really want your precious RAM drive, I've heard rumors that it's tucked away on your Windows Server 2003 CD under the names RAMDISK.IN_ and RAMDISK.SY_, and that there is a way to add a RAM drive to your Windows PE disk. (And no, I haven't heard any rumors about Windows Server 2008.)

  • The Old New Thing

    If you return FALSE from DLL_PROCESS_ATTACH, will you get a DLL_PROCESS_DETACH?


    If you return FALSE from DLL_PROCESS_ATTACH, will you get a DLL_PROCESS_DETACH?





    All three answers are correct, for different formulations of the question.

    From the kernel's point of view, the answer is a simple Yes. If a DLL's entry point returns FALSE to the DLL_PROCESS_ATTACH notification, it will receive a DLL_PROCESS_DETACH notification.

    However, most C and C++ programs do not use the raw DLL entry point. Instead, they use the C runtime entry point, which will have a name something like DllMainCRTStartup. That entry point function does work to manage the C runtime library and calls your entry point (which you've probably called DllMain) to see what you think.

    If you compiled your program prior to around 2002 and your DllMain function returns FALSE in response to the DLL_PROCESS_ATTACH notification, then the C runtime code says, "Oh, well, I guess I'm not running after all" and shuts itself down. When the kernel calls the C runtime entry point with the DLL_PROCESS_DETACH notification, the C runtime says, "Oh, I'm already shut down, thanks for asking" and returns immediately, which means that your entry point is not called with the DLL_PROCESS_DETACH notification. In other words, if you wrote your program prior to around 2002, the answer is No.

    Sometime in 2002 or maybe 2003, the C runtime folks changed the behavior. If your DllMain function returns FALSE in response to the DLL_PROCESS_ATTACH notification, you will nevertheless get the DLL_PROCESS_DETACH notification. In other words, if you wrote your program after around 2002 or maybe 2003, then the answer is Yes. Why change? Maybe they wanted to match the kernel behavior more closely, maybe they considered their previous behavior a bug. You'll have to ask them.

    What does this mean for you, the programmer? Some people may look at this and conclude, "Well, now that I know how each of the specific scenarios works, I can rely on knowing the behavior that results from the scenario I'm in. For example, since I'm using Visual Studio 2008, the answer is Yes." But I think that's the wrong conclusion, because you usually do not have total control over how your program is compiled and linked. You may share your code with another project, and that other project may not know that you are relying on the behavior of a specific version of Visual Studio 2008; they will compile your program with Borland C++ version 5.5,¹ and now your program is subtly broken. My recommendation is to write your DllMain function so that it works correctly regardless of which scenario it ends up used in. (And since you shouldn't be doing much in your DllMain function anyway, this shouldn't be too much of a burden.)


    ¹I do not know what the behavior of Borland C++ version 5.5 is with respect to returning FALSE from DllMain. I didn't feel like doing the research to find a compiler whose behavior is different from Visual Studio 2008, so I just picked one at random. I have a 50/50 chance of being right.

  • The Old New Thing

    Why, when you sort by name, doesn't it actually sort by name?


    When you right-click on the desktop or in an Explorer window and select "Sort by... Name", why doesn't it actually sort by name?

    Because "Sort according to the default sort order for the column whose title is... Name" is too long.

    The default sort order for the first column (whose name is "Name") is to sort by name, mostly. The actual sort order for the desktop and file folders (note: implementation detail, subject to change at any time) is really a two-tiered sort. First, the items are sorted into buckets; the first bucket contains the virtual folders, the second bucket contains file folders (directories), and the third bucket contains regular files. Sorting within the first bucket is done by the "item order"; sorting within the second and third buckets is by name. (And it's not by ASCII code any more. There's also special treatment for numbers and periods.)

    The "item order" (a term I just made up) for My Computer, My Documents, and Recycle Bin were specifically chosen in Windows 95 so that the icons on the desktop appeared in that order. I believe it was in Windows 2000 that the order was changed to My Documents, My Computer, Recycle Bin in order to put the focus on document management.

    (And those who have read Appendix A of my book will know what sort of application compatibility problems arose from that simple change.)

  • The Old New Thing

    The unwritten rule of riding a Seattle Metro bus


    The Metro King County transit site has all the facts about how to ride the bus, but there's another rule that is applied by convention rather than by any formal codification:

    For some reason, and I see this only in Seattle, it is customary to say Thank you to the bus driver as you get off the bus.

    Tip for new riders: If you aren't familiar with the area, you can ask the bus driver to announce the stop you intend to get off at.

    Bonus tip for bicyclists: There is an experimental program running this summer to allow bicyclists to ride out-of-service buses across the 520 bridge for free. You have to get on at Evergreen Point and get off at Montlake (or vice versa). This is in addition to the existing policy of allow bicyclists to ride out-of-service buses across the bridge (paying the normal fare), eastbound as far as 51st St, assuming the bus is heading that way. (This bonus tip is not that helpful to Microsoft employees, who already get free bus passes and a special bike shuttle, but I figured I'd toss it out there.)

  • The Old New Thing

    The gradual erosion of the car trip experience


    How will kids today learn to get along with their siblings? I just learned that another of the basic childhood conflict resolution scenarios has disappeared, thanks to the dual-screen DVD player and entertainment system for your car, so each kid can remain content without the burden of having to interact with their annoying brother or sister. The traditional car ride games will slowly fade away, replaced with questions like, "Grandma, where's the Nintendo?"

    Why stop there? Why not just equip the car with tranquilizing gas in the back seat? The kids go in, you knock them unconscious, and you wake them up when you arrive at the destination.

    One of my friends told me that as a child, she objected that her brother was looking out her window, a degree of territoriality I was previously not aware of. Her parents naturally ridiculed her for making such a complaint, and I think she turned out okay.

  • The Old New Thing

    What's with this MSH_MOUSEWHEEL message?


    The hardware folks had this mouse wheel thing they were making, and they needed a way to get applications to support the mouse. Now, one way of doing this was to say, "Well, we'll start selling this wheel mouse, but no applications can use it until the next version of Windows is released, one that supports the wheel." Of course, that would have meant waiting until Windows NT 4 came out, and who know when that would be. Plus it meant that people would have to upgrade Windows in order to take advantage of their fancy new mouse. As you can imagine, they weren't too pleased with the "wait a few years" plan.

    In the interim, they proposed a stopgap mechanism for applications to respond to the mouse wheel. Enter the zmouse.h header file and its MSH_MOUSEWHEEL registered message. When you installed the wheel mouse driver, it listened for wheel events from the hardware and posted this new message when the mouse wheel turned, and applications could just respond to either the WM_MOUSEWHEEL message (if running on a version of Windows that supported the message) or the MSH_MOUSEWHEEL message (if running on an older version of Windows that didn't). Unfortunately, the two messages behave differently, so it's not a simple matter of writing

    if (uMsg == WM_MOUSEWHEEL || uMsg == g_msgWheel) {
     ... do wheel stuff ...

    (These next few paragraphs summarize what is already spelled out in MSDN; you can skip them if you already know how the messages work.)

    First, let's look at WM_MOUSEWHEEL. This message is delivered to the window that has focus (in the SetFocus sense). If the window procedure doesn't handle the message and just passes it through to the DefWindowProc function, then the DefWindowProc function forward the message to the window's parent. In this way, the WM_MOUSEWHEEL message automatically "bubbles outward" from the focus window up the parent chain until somebody finally handles the message (or it goes all the way to the top without being handled at all).

    On the other hand, the MSH_MOUSEWHEEL message works from the outside in. It is delivered to the foreground window (in the SetForegroundWindow sense). If the window procedure doesn't want to handle the message, it can forward the message to child windows of its choice, until one of them returns TRUE to indicate that the message was handled, or until no further candidates exist.

    I'll summarize these differences in a table, since people seem to like tables so much.

    Propagation direction Inside-out Outside-in
    Propagation mechanism DefWindowProc SendMessage
    Handling Automatic Manual: Application checks return value
    from child to determine what to do next
    Return value if processed Zero TRUE
    Return value if not processed DefWindowProc FALSE

    Notice that WM_MOUSEWHEEL is much simpler, and the inside-out propagation mechanism retains the spirit of other messages such as WM_CONTEXTMENU and WM_SETCURSOR. Why can't MSH_MOUSEWHEEL do it the same way?

    Well, first of all, MSH_MOUSEWHEEL doesn't have the luxury of being able to modify the DefWindowProc function. After all, that's the whole point of introducing the message in the first place, because we're trying to add wheel support to an older operating system that predated mouse wheels. Put in other words, if we could modify DefWindowProc to handle the MSH_MOUSEWHEEL message, then we wouldn't have needed the MSH_MOUSEWHEEL message to begin with; we would've just modified DefWindowProc to handle the WM_MOUSEWHEEL message.

    The argument in the previous paragraph is a frustratingly common one. Given a problem X and a workaround Y, somebody will ask, "Why didn't you use method Z?" If you look at method Z, though, you'll see that it suffers from the exact same problem X.

    Here's a real-world example of the "confused workaround":

    "Since the I-90 bridge is closed, I can't take the 550 bus to get from Bellevue to Safeco Field. Instead, I'm going to take the 230 to Redmond, and then change to the 545."

    — Well, that's silly. Why not take the 245 to Eastgate, and then change to the 554? It's a lot faster.

    "Um, the 554 uses the I-90 bridge, too."

    Okay, so you can't change DefWindowProc, but why not at least propagate the MSH_MOUSEWHEEL from the inside out instead of from the outside in?

    Starting with the focus window assumes you can even find out what the focus window is, but if you had paid attention to the Five Things Every Win32 Programmer Should Know, you would have known that each thread has its own focus window. (Not nitpickily true, but true enough.) Consequently, when the helper program that injects MSH_MOUSEWHEEL messages calls GetFocus, it just gets its own focus window, not the focus window of the thread that controls the foreground window. (Remember, we're talking 1996, long before the GetGUIThreadInfo function was invented. History buffs can find out more from Meet The Inventor of the Mouse Wheel.) Since inside-out was off the table, that pretty much forced outside-in.

    Now that you know how mouse wheel messages work, you can explain the behavior this customer is seeing:

    I'm seeing the WM_MOUSEWHEEL message being delivered to the wrong child window. I have a parent window with two children. Even though I move the mouse pointer over child 1, the WM_MOUSEWHEEL goes to child 2.
  • The Old New Thing

    Psychic debugging: Why can't StreamReader read apostrophes from a text file?


    As is customary, the first day of CLR Week is a warm-up. Actually, today's question is a BCL question, not a CLR question, but only the nitpickers will bother to notice.

    Can somebody explain why StreamReader can’t read apostrophes? I have a text file, and I read from it the way you would expect:

    StreamReader sr = new StreamReader("myfile.txt");

    I expect this to print the contents of the file to the console, and it does—almost. Everything looks great except that all the apostrophes are gone!

    You don't have to have very strong psychic powers to figure this one out.

    Here's a hint: In some versions of this question, the problem is with accented letters.

    Your first psychic conclusion is that the text file is probably an ANSI text file. But StreamReader defaults to UTF-8, not ANSI. One version of this question actually came right out and asked, "Why can't StreamReader read apostrophes from my ANSI text file?" The alternate version of the question already contains a false hidden assumption: StreamReader can't read apostrophes from an ANSI text file because StreamReader (by default) doesn't read ANSI text files at all!

    But that shouldn't be a factor, since the apostrophe is encoded the same in ANSI and UTF-8, right?

    That's your second clue. Only the apostrophe is affected. What's so special about the apostrophe? (The bonus hint should tip you off: What's so special about accented letters? What property do they share with the apostrophe?)

    There are apostrophes and there are apostrophes, and it's those "weird" apostrophes that are the issue here. Code points U+2018 (‘) and U+2019 (’) occupy positions 0x91 and 0x92, respectively, in code page 1252, and these "weird" apostrophes are all illegal lead bytes in UTF-8 encoding. And the default behavior for the Encoding.UTF8Encoding encoding is to ignore invalid byte sequences. Note that StreamReader does not raise an exception when incorrectly-encoded text is encountered. It just ignores the bad byte and continues as best it can, following Burak's advice.

    Result: StreamReader appears to ignore apostrophes and accented letters.

    There are therefore multiple issues here. First, you may want to look at why your ANSI text file is using those weird apostrophes. Maybe it's intentional, but I suspect it isn't. Second, if you're going to be reading ANSI text, you can't use a default StreamReader, since a default StreamReader doesn't read ANSI text. You need to set the encoding to System.Text.Encoding.Default if you want to read ANSI text. And third, why are you using ANSI text in the first place? ANSI text files are not universally transportable, since the ANSI code page changes from system to system. Shouldn't you be using UTF-8 text files in the first place?

    At any rate, the solution is to decide on an encoding and to specify that encoding when creating the StreamReader.

    This exercise is just another variation on Keep your eye on the code page.

  • The Old New Thing

    Wedding + two-year-old flower girl = wildcard


    I was in San Francisco this weekend for a wedding. The flower girl was the bride's two-year-old niece, and when you add a two-year-old to the wedding party, you never know what's going to happen, because two-year-olds don't understand the world the same way adults do.

    During the unity candle ceremony, the two-year-old pushed her way to the table, joining the bride and groom, in order to get a front-row seat for the ritual. And then when the unity candle was lit, she tried to blow it out.

    Because when you're two years old, the only time you see people make a big deal about lighting a candle is when it's atop a birthday cake, and you know what to do with birthday candles!

  • The Old New Thing

    Icons and cursors know where they came from


    If you create an icon by calling LoadIcon, the window manager loads the specified icon from the module you specified, but it also remembers where the icon came from. (This discussion also applies, mutatis mutandis to cursors, but I will just talk about icons to avoid awkardness.) When you pass the LR_COPYFROMRESOURCE flag to the CopyImage function, the window manager goes back to the original icon source to create the copy you requested rather than blindly stretching the pixels of the icon you passed in.

    Remember that an ICO file represents not just one icon but rather a collection of icons (known as an "icon group"), each at a different size or color depth. The intent is that each icon in the icon group depicts the same underlying image, just tuned for particular settings. (Now, mind you, there is no enforcement of this intent. If you make your 16×16 image a smiling-face and your 32×32 image a barking dog, well, then that's your problem.) For example, a single ICO file might contain a 16×16 image, a 32×32 image, and a 48×48 image. If somebody asks for the icon at one of those sizes, then the corresponding image is used. On the other hand, if somebody asks for, say, the 24×24 image, the window manager will take the 32×32 image and stretch it to the necessary size.

    You can recover this "hidden source information" with the GetIconInfoEx function (new for Windows Vista). If the icon was loaded by ordinal, then the szResName is an empty string and the ordinal is placed in the wResID member. If the icon was loaded by name, then wResID is zero and szResName contains the resource name.

    This is just some background information about icons (and cursors). Next time, we'll put this information to use to solve a problem.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    What does each country claim for its own?, greatest hits


    A little while back, I invited readers to describe what students are taught (or end up believing) are the greatest contributions of their country. Many people strayed from the "what students are taught" part of the exercise, but I didn't mind too much as long as you were funny.

    Here are some of my favorites:

    Representing Greece is Pi, who writes,

    In Greece I was also taught that Greeks invented democracy. Other than that Greeks are supposed to have laid the groundwork for the development of philosophy, mathematics, physics, biology and pretty much every other greek named thing as a science (except for economics).

    Greeks claim to have organized the first olympic games some 2800 years ago. And back then there was some guy named Homer whose stories are still read today occasionally. He was also the template for the creation of a character in the Simpsons.

    The sad thing is that my compatriots often think they are cool by default because of these things and they don't have to accomplish anything by themselves.

    Dan reminds us that

    Sweden is pretty proud of Dynamite (Alfred Nobel), and the safety match.

    I enjoy that juxtaposition. Do you use a safety match to light your dynamite?

    For France, we have bahbar (who pseudonym is a reference to another great French contribution to humanity):

    - beheadings (just kidding)

    Rafael Vargas points out a Spanish invention that is very important to students:


    Rob points out that some inventions can be used for evil:

    - the first moving picture was shot in Leeds, West Yorkshire, though by a Frenchman (so we're not responsible for Charlie's Angels: Full Throttle).

    Leonardo Brondani Schenkel adds an important Brazilian contribution I had overlooked:


    Dan summarizes how all these claims are manifested on Wikipedia:

    "John Doe was an Italian-born[1] Jew[2] of Dutch[3] and Lithuanian[4] descent who was raised in Canada[5] and lived in Argentina for several years as an adult[6]. He is perhaps best known for inventing the belly-button-lint remover[citation required]."

    JS Bangs points out one of Romania's great contributions for which it doesn't get enough credit:

    [W]e defeated the Turks over and over, and thus kept the Ottomans from raping and pillaging their way all the way to France. So we like to take credit for the survival of Western Europe.

    At least it beats being known for providing the soundtrack to the Numa Numa video.

    Canadian Ens happens to mention "the CanadArm" in an extensive list of Canadian inventions. From what I can tell, Canadians are taught that NASA's job is to launch the CanadArm into space so it can move stuff around.

    Zheng Hua was the first of many to call out the Four Great Inventions of ancient China which students are drilled in from a young age.

    Omer van Kloeten explains the Israeli approach:

    In Israel we pretty much take credit for every invention ever made by any Jewish person in the 5000 year history of the religion.

    Also, even though it's not inventions, we celebrate the fact that we survived (which for us is the same as "won") the wars of 1947, 1956, 1967, 1969, 1973, etc. while mostly being heavily outnumbered.

    I remember it being explained to me by a Jewish friend that nearly all Jewish holidays are based on a celebration of the fact that "They didn't kill all of us!"

    Laurent points out a common theme: A country will claim credit for the deeds of an immigrant, and will also claim credit for the accomplishments of somebody who was born in the country but made the discovery while an expatriate. Heck, I wouldn't be surprised if there was a case of a country who claimed credit for somebody who merely stopped in the country to have lunch.

    A South African friend mentioned to me privately that South African are taught that their country invented the Kreepy Krauly pool vacuum cleaner and the dolos.

    Glenn S tells us what Norway is proud of. It's too long to quote here, but it's worth reading because, unlike many other people who posted lists of accomplishments, Glenn's is written with the right sense of humor, playfully acknowledging that some of the claims may not be entirely fair.

Page 2 of 4 (37 items) 1234