January, 2008

  • The Old New Thing

    How does the calculator percent key work?


    The Windows calculator percent sign works the same way as those cheap pocket calculators (which are often called four-function calculators even though they have around six function nowadays). What you first have to understand is that the percent key on those pocket calculators was not designed for mathematicians and engineers. It was designed for your everyday person doing some simple calculations. Therefore, the behavior of the key to you, an engineer, seems bizarrely counter-intuitive and even buggy. But to an everyday person, it makes perfect sense. Or at least that's the theory.

    Let's look at it from the point of view of that everyday person. Suppose you want to compute how much a $72 sweater will cost after including 5% tax.¹ Pull out your handy pocket calculator² (or fire up Calc if you don't have a pocket calculator) and type

    72 + 5% =

    The result is 75.6, or $75.60, which is the correct answer, because 5% of 72 is 3.6. Add that to 72 and you get 75.6.

    Similarly, suppose that sweater was on sale at 20% off. What is the sale price?

    72 − 20% =

    The result is 57.6 or $57.60. This is the correct answer, because 20% of 72 is 14.4. Subtract that from 72 and you get 57.6.

    You can chain these percentage operations, too. For example, how much will you have to pay for that 20%-off sweater after adding 5% tax?

    72 − 20% + 5% =

    The result is 60.48. A mathematician or engineer would have calculated the same result via the equivalent computation:

    72 × 0.80 × 1.05 =

    Okay, now that we see how the calculator product designer intended the percent key to be used, let's look at what the calculator engineer it has to do in order to match the specification. When the user enters A + B % =, the result should be A × (1 + B/100) or A + (A × B/100) after you distribute the multiplication over the addition. Similarly, when the user enters A − B % =, the result should be A × (1 − B/100) or A − (A × B/100).

    Aha, the calculator engineer says, we can achieve this result by defining the percent key as follows:

    When the user enters a value, an operator, a second value, and then the percent key, the first two values are multiplied and the product divided by 100, and that result replaces the second value in the ongoing computation.

    Let's walk through that algorithm with our first example.

    You typeRemarks
    72First value is 72
    +Operation is addition
    5Second value is 5
    %72 × 5 ÷ 100 = 3.6
    3.6 becomes the new second value
    =72 + 3.6 = 75.6, the final result

    If you watch the display as you go through this exercise, you will even see the number 3.6 appear in the display once you press the % key. The percentage is calculated and replaces the original value in the ongoing computation.

    This algorithm also works for the chained percentages.

    You typeRemarks
    72First value is 72
    Operation is subtraction
    20Second value is 20
    %72 × 20 ÷ 100 = 14.4
    14.4 becomes the new second value
    +72 − 14.4 = 57.6, intermediate result
    57.6 is the new first value
    Operation is addition
    5Second value is 5
    %57.6 × 5 ÷ 100 = 2.88
    2.88 becomes the new second value
    =57.6 + 2.88 = 60.48, the final result

    This even works for multiplication and division, but there is much less call for multiplying or dividing a number by a percentage of itself.

    500 × 5 % =

    The result of this is 12,500 because you are multiplying 500 by 5% of 500 (which is 25). The result of 500 × 25 is 12,500. You aren't computing five percent of 500. You're multiplying 500 by 5% of 500. (It appears that the authors of this Knowledge Base article didn't consult with the calculator engineer before writing up their analysis. The percent key is behaving as designed. The problem is that the percent key is not designed for engineers.)

    What if you want to compute 5% of 500? Just pick a dummy operation and view the result when you press the percent key.

    500 + 5 %

    When you hit the percent key, the answer appears: 25. You could've used the minus key, multiplication key, or division key instead of the addition key. It doesn't matter since all you care about is the percentage, not the combined operation. Once you hit the % key, you get your answer, and then you can hit Clear to start a new calculation.


    ¹In the United States, quoted prices typically do not include applicable taxes.

    ²In my limited experiments, it appears that no two manufacturers of pocket calculators handle the percent key in exactly the same way. Casio appears to handle it in a manner closest to the engineering way. TI is closer to the layman algorithm. And when you get into cases like 1 ÷ 2 %, calculators start wandering all over the map. Should the answer be 50, since 1/2 is equal to 50%? Or should it be 0.005 since that is the numeric value of 0.5%? Should that answer appear immediately or should it wait for you to hit the equals sign? I don't know what the intuitive result should be either.

  • The Old New Thing

    No matter where you put an advanced setting, somebody will tell you that you are an idiot


    There are advanced settings in Windows, settings which normal users not only shouldn't be messing with, but which they arguably shouldn't even know about, because that would give them just enough knowledge to be dangerous. And no matter where you put that advanced setting, somebody will tell you that you are an idiot.

    Here they are on an approximate scale. If you dig through the comments on this blog, you can probably find every single position represented somewhere.

    1. It's okay if the setting is hidden behind a registry key. I know how to set it myself.
    2. I don't want to mess with the registry. Put the setting in a configuration file that I pass to the installer.
    3. I don't want to write a configuration file. The program should have an Advanced button that calls up a dialog which lets the user change the advanced setting.
    4. Every setting must be exposed in the user interface.
    5. Every setting must be exposed in the user interface by default. Don't make me call up the extended context menu.
    6. The first time the user does X, show users a dialog asking if they want to change the advanced setting.

    If you implement level N, people will demand that you implement level N+1. It doesn't stop until you reach the last step, which is aggressively user-hostile. (And then there will also be people who complain that you went too far.)

    From a technical standpoint, each of the above steps is about ten to a hundred times harder than the previous one. If you put it in a configuration file, you have to write code to load a parser and extract the value. If you want an Advanced button, now you have to write a dialog box (which is already a lot of work), consult with the usability and user assistance to come up with the correct wording for the setting, write help text, provide guidance to the translators, and now since it is exposed in the user interface, you need to write automated tests and add the setting to the test matrices. It's a huge amount of work to add a dialog box, work that could be spent on something that benefits a much larger set of customers in a more direct manner.

    That's why most advanced settings hang out at level 1 or, in the case of configuring program installation, level 2. If you're so much of a geek that you want to change these advanced settings, it probably won't kill you to fire up a text editor and write a little configuration file.


    Joel's count of "fifteen ways to shut down Windows" is a bit disingenuous, since he's counting six hardware affordances: "Four FN+key combinations... an on-off button... you can close the lid." Okay, fine, Joel, we'll play it your way. Your proposal to narrow it down to one "Bye" button, still leaves seven ways to shut down Windows.

    And then people will ask how to log off.

  • The Old New Thing

    The history of the Windows XP common controls


    In the beginning, there was one control library, namely USER, the window manager itself, which provided buttons, static controls, edit controls, scroll bars, list boxes, and combo boxes. These controls were under the purview of the window manager team.

    In Windows 3.1 a second control library known as the shell common controls was added, but the library really didn't come into it own until Windows 95, where it consisted of the list view, header, tree view, tooltip, toolbar, status bar, track bar, tab, updown, progress, hotkey, and animation controls. These controls were originally custom controls written by the shell team for use in Explorer, but since they seemed to be generally useful, time was budged to do the extra work to make the controls more suitable for general use, testing the controls in combinations and scenarios that Explorer itself didn't use, and putting together formal documentation.

    The shell common controls library underwent many changes over the years, whereas the core intrinsic controls in the window manager changed much more conservatively.

    With Windows XP, the visual design team wanted to give the look of Windows a new life. Changing the non-client area (such as the window frame) was comparatively straightforward, since programs didn't have much control over that part of the window anyway. As a result, they get the Windows XP look "for free".

    The client area is another story. Programs are in control of their client area, where they can place controls that come with Windows, their own custom controls, or controls obtained from a third party library. Making major changes to the core controls or the common controls would be a high-risk endeavor since there are thousands upon thousands of Windows program that not only use them, but use them in all sorts of crazy ways.

    The initial stab at resolving these two conflicting goals (making major changes to these controls to increase visual appeal and functionality while simultaneously not changing them to maintain compatibility) was to create a new DLL that would contain the "fancy new version" of the core controls as well as the shell common controls. The old DLLs USER32 and COMCTL32 stayed where they were, so that old programs continued to get the behavior they were expecting, and the new XP-style controls were placed in a DLL named UXCTRL.DLL. UX stands for user experience, which was the hot new buzzword at the time. To avoid name collision with the old style controls, the new controls got new names beginning with Ux. For example, the UXCTRL version of the button control was called UxButton.

    New features could be added to these new Ux controls with wild abandon without heed for backward compatibility since they were brand new controls. There was nothing they had to be compatible with. Explorer was changed to use these new controls instead of the old stodgy controls, and everything worked great.

    Or so it seemed.

    We thought we had cleverly sidestepped the backward compatibility problem by creating entirely new controls, but doing that created a whole new category of compatibility bugs. Even though it's completely undocumented and unsupported, programs like to grovel into the internal data structures of other programs or otherwise manipulate those programs' windows. In Explorer's case, it turns out that a lot of programs like to go spelunking around Explorer's window hierarchy and use functions like FindWindow and EnumChildWindows to find the object of their affections. For example, a program might use EnumChildWindows to enumerate all the child windows of an Explorer browser, and then use GetClassName and lstrcmpi(szClassName, TEXT("button")) to look for a specific control. In this example, the target was a button, but it could have been a list view or a tool bar. Since all the new XP-style controls were named things like UxButton and UxListView, these programs which looked for a button by comparing against the string "button" stopped working.

    Of course, there was no guarantee that Explorer would even use buttons at all; Explorer was completely within its rights to revamp its user interface. But that's not much consolation to the customers who paid good money for these programs, especially since magazine columnists are the types of people most likely to be running (or indeed even writing!) strange off-the-wall programs that pull these sorts of nasty stunts in the first place.

    Okay, so it is now a compatibility requirement that all the new window classes have the same names as their old counterparts. This created an impasse, since these controls needed to be created by dialog boxes, and therefore they had to be globally-registered window classes. But you can't have two global window classes with the same name, because that would create ambiguity over which one the caller was asking for.

    More brainstorming ensued, and a Plan C emerged. The common controls library would take advantage of side-by-side assemblies and use the application manifest to control which DLL a given window class name would resolve to. Thus was born a new DLL also called COMCTL32, but with a new version number—version 6. Old programs would get version 5.82 just like they did in Windows 2000. New programs would have to use a manifest to specify that they wanted version 6.

    Once again, the solution came with a new problem. Since the entire COMCTL32 library got split into two versions, this meant that there were two versions of the image list code. Whole new scenarios emerged, such as putting a version 5 image list in a version 6 tree view, or vice versa. (As the linked thread notes illustrates, not all of the problems with cross-version scenarios were caught in the initial release and had to wait for a service pack for the fix to become available.)

  • The Old New Thing

    Clean-up functions can't fail because, well, how do you clean up from a failed clean-up?


    Commenter Matt asks how you're supposed to handle failures in functions like fclose or CloseHandle. Obviously, you can't. If a clean-up function fails, there's not much you can do because, well, how do you clean up from a failed clean-up?

    These clean-up functions fall into the category of "Must not fail for reasons beyond the program's control." If a program tries to close a file and it gets an error back, what can it do? Practically speaking, nothing. The only way a clean-up function can fail is if the program fundamentally screws up, say by attempting to close something that was never open or otherwise passing an invalid parameter. It's not like a program can try to close the handle again (or worse go into loop closing the handle repeatedly until it finally closes).

    Remember this when writing your own clean-up functions. Assuming the parameters are valid, a clean-up function must succeed.

    (I will now ruin my rhetorical flourish by yammering about the fclose function because if I don't, people will bring it up in the comments anyway. The fclose function does extra work before closing, and that extra work may indeed run into problems, but the important thing is that when fclose returns, the stream is well and truly closed.)

    Addendum: Once again I wish to emphasize that while it may be possible for functions like fclose to run into errors while they are closing the stream, the point is that the result of the call to fclose is always a closed stream. I think most of the comments are losing sight of the point of my article and rat-holding on the various ways fclose can run into errors. That's not the same as failing. It never fails; it always succeeds, but possibly with errors.

  • The Old New Thing

    In steady state, only geeks install Windows, but the hard part is getting to that steady state


    Commenter BryanK notes that only already-technical people (re)install Windows; commenter Stu estimates the percentage at 99%. That may be true in the steady state, but the hard part is getting to that steady state.

    When a new version of Windows is released, the steady state is disrupted. At that point, most people installing Windows aren't technical. They're your technology columnist who is installing Windows and viewing it through the eyes of a non-technical user, then writing a column about it. They're your average consumer who wants to check out this new operating system. These are the crazy people who stayed up late to buy the product at the stroke of midnight, and they're going to kick off an upgrade install once they get home. These initial impressions are crucial, and innundating the user with geeky questions they can't answer is not going to generate good buzz.

    The steady state is also disrupted every year at Christmas. The technology columnists are not as big a part of the picture, but the non-technical end users are still around, and Christmas is a common trigger for upgrading one's system.

    So even though non-technical people rarely install Windows, the steady state is upset every year. What's more, whenever a new release of Windows comes out all¹ the people who are installing Windows are non-technical. That's why it's important for the installation process to be as friendly to non-technical users as possible.

    ¹The word "all" here is about as accurate as the word "only" in the original comment.

  • The Old New Thing

    Why do registry keys have a default value?


    In addition to all the named values you can create underneath a registry key with the RegSetValueEx function, there is also the so-called default value which you obtain by passing NULL or a pointer to a null string as the lpValue. This default value is also the value set and retrieved when you call RegSetValue and RegQueryValue. What's the deal with this default value?

    The original 16-bit registry didn't have named values. All it had were keys, and associated with each key was a single piece of data: a string. The functions that operated on this data were RegSetValue and RegQueryValue, which explains why those functions (1) don't have a lpValue parameter and (2) set and retrieve only string data. Because back in the 16-bit world, that's all you had.

    In the conversion to Win32, the registry gained new capabilities, such as storing data in formats beyond simple strings, and storing multiple pieces of data under a single key, using a name to distinguish them. What used to be called simply "the value of a registry key" (for since there was only one, there was no need to give it a name) now goes by the special name the default value: It's the value whose name is null.

    There's nothing particularly special about the default value aside from its unusual name. A named value need not exist, and if it exists, the data type could be anything. Similarly, the default value need not exist, and its type can be anything. At this point, it's just a value with a strange name.

  • The Old New Thing

    When computer programmers dabble in economics: Paying parking tickets


    One of my colleagues has a degree in economics, and sometimes it manifests itself in strange ways.

    My colleague moved to a new apartment building and rented a parking space in the building's garage. After a month of noticing that there was usually an empty parking space or two on the street, my colleague made the economic calculation that the risk of not finding a parking space nearby was outweighed by the savings of not paying for a monthly parking space.

    After a few more months, my colleague started experimenting with the alternate side of the street parking rules and noticed that they tended not to be enforced early in the morning. Once again, after some mental calculations, the extra few hours of sleep were deemed worth the additional cost of the occasional parking ticket.

    The saga continues. My colleague then determined that the city doesn't really care that much if you don't pay your parking ticket. (I personally find this hard to believe, but that's how my colleague described it, so there you have it.) The unpaid tickets piled up.

    And then something happened to put an end to this little scheme: The prospect of home ownership. My friend planned to move out of the apartment building and buy a house in a different part of the city.

    While the city may not care about unpaid parking tickets, banks definitely do, and it was adversely affecting the interest rates on the home loan offers. My colleague sat down and did the math and calculated that the time-discounted savings over the life of the loan outweighed the present cost of paying off all the parking tickets.

    Off to the parking ticket payment office we go. "Hi. I'd like to pay my parking tickets." The person at the desk took down the pertinent information and went to the computer to print out the tickets so they could be paid. This was back in the days of dot matrix printers and tractor-feed paper, so the printer buzzed noisily and could be heard throughout the room.

    The tickets printed.

    And printed.

    And printed.

    People in the office started to take notice, wandered over to the printer to see what was going on, and then, once they realized what was happening, began to clap and cheer. Handing over the check to pay for the tickets earned my colleague a standing ovation.

    (By the way, today is a parking holiday in Seattle.)

    [Note: An incomplete version of this article was mistakenly published a day early. It has been updated to the finished version and moved to its correct publication date.]

  • The Old New Thing

    Fact of life: People can't see things that are right in front of them


    A bug report came in:

    When I go to the Power Options control panel and select Edit Plan Settings, the Turn off display combo-box is disabled. Is this a bug?

    Shortly thereafter, this response was submitted:

    Do you see a big yellow warning over the Turn off display that says that some settings are managed by your system administrator, and a link called Why can't I change some settings?

    The reply:

    Yes, my machine is joined to a domain, and I see that yellow warning.

    This is a fact of life. People can't see what is right in front of their face. Even though there's a warning right above the disabled item explaining that it can't be changed due to an administrative setting, even though there's a link on the page whose text directly addresses the issue they are asking about, even though they confirm the existence of the explanatory text when asked, they still don't read it or understand it. It's another case of inattentional blindness. You are so focused on the task of clicking on the combobox that you completely disregard any other information because you simply aren't expecting it to be there.

  • The Old New Thing

    Windows is not an MFC delivery channel


    Depending on what version of Windows you're running, there may be a variety of support DLLs for things that aren't formal product components, but which are merely along for the ride. For example, Windows 95 came with MFC30.DLL because the Fax Viewer was written with the help of MFC 3.0. But if you look at Windows 98, MFC30.DLL is gone.

    What happened?

    What happened is that Windows 98 didn't have a fax viewer that used MFC 3.0. The fact that some MFC 3.0 DLLs wound up on the machine with Windows 95 was merely a side effect of the implementation and not a part of the product specification. And in fact, if you chose not to install the Fax Viewer during Windows 95 setup, you wouldn't have gotten MFC30.DLL at all either, because MFC30.DLL wouldn't have been needed.

    We had a category of Windows 98 compatibility bugs from programs that assumed that MFC30.DLL was a contractual part of Windows. If the tester did a minimal install of Windows 95 and then installed the application, the application wouldn't run there either. The application vendor simply assumed that MFC was part of Windows, even though it wasn't. In other words, the program didn't work even on Windows 95. Is it a bug in Windows 98 if the program didn't work on Windows 95?

    This problem persists today. People go scrounging around the binaries that come with Windows looking for something they can remora. And then they're surprised when those binaries change or vanish entirely. For example, one customer had reverse-engineered the Kodak image viewer in Windows 2000 and wanted to keep using it in Windows XP. But those components are not included in Windows XP; the Kodak image viewer was merely a stopgap solution until the Windows XP fax and image viewer came along. (The linked Knowledge Base article has more information on that product.) I mention this because that customer, a Fortune 500 company, was trying to copy the files from Windows 2000 and install them onto a Windows XP machine and actually came to us asking for help in what may very well have been a violation of the Windows license agreement! (And certainly a violation of Microsoft's agreement with Kodak.)

    (I now predict that everybody will comment on the last two sentences and completely ignore the point of this article.)

  • The Old New Thing

    Even without a nitpicker's corner, I have to worry about nitpickers


    Even without a nitpicker's corner, I have to worry about nitpickers. I just have to do it in a more subtle way.

    Here are some examples of changes I've made to upcoming entries in order to forestall nitpicking:

    Original text Revised text Reason
    ... entries in our list... ... entries in our table... The entries are kept in an array, but writing "list" may cause some people to nitpick that an array is not a list.
    ... this function returns X... ... this function can be asked to return X... The function returns different things based on what the caller requests, but the only case we're interested in right now is the case of X.
    ... X affects only Y. ... X typically affects only Y. Again, I have to add the qualifier to protect against the case where a program intentionally broadens the scope of X.
    ... X isn't a problem because... ... X isn't usually a problem because... There can be cases where X is a problem because the program explicitly created the problem for itself, so I have to put in a qualifier. Indeed, later in the article I give an example of how a program can cause this problem, so I'd better leave myself some wiggle room at the expense of rhetorical power.
    ... a holiday.... ... a holiday in the United States... Otherwise somebody would make some smart-alec remark like "It's not a holiday where I live." [Typo fixed: 10am]
    ... the kernel .... ... the exception dispatch code... To avoid confusion between "the kernel" and "kernel mode".
    ... 64KB ... ... about 64KB... Because the limit is actually 65280 bytes.

    What's scary is that I've noticed that I begun pre-emptively nitpicking my own entries while I'm writing them. In the balance between writing something that reads more naturally and something that is more resiliant to nitpicking, I've unfortunately started preferring the latter.

    Observant readers may have noticed that I've slowly introduced a section called "Pre-emptive snarky comment" wherein I try to anticipate drive-by "Hey wouldn't it be hilarious if I ridiculed Microsoft on a Microsoft employee's blog?" comments. It seems to be largely successful, although sometimes people will post the identical snarky comment that I pre-empted. These are probably the people who talk just to enjoy the sound of their own voice.

    An extension of this is the "Now that you brought up something that sucks, I'm going to tell you that it sucks" phenomenon. This is pretty much guaranteed whenever I bring up anything that is related to UAC and security, since it appears that everybody agrees that UAC sucks, so any blog entry that talks about elevation invariably leads to comments about how UAC sucks. There are also popular tangents, such as any article that mentions installing software turning into a "post your complaints about setup here" thread.

    Some people are more indiscriminate and merely bash Vista whenever they get a chance, such as using a story about the psychology of how people fail to process information that they see to rant about how it's hard to copy text out of the event viewer.

    (That article about how people fail to process information that they see was indeed an unmitigated disaster. Everybody got into arguing over how the message should have been presented so the user would be more likely to see it, but that completely misses the point. The user positively confirmed, "I see the yellow warning." The problem wasn't that the user didn't see the message; the response confirmed that the user saw the message just fine. What the user didn't do was process the information. It's my fault for choosing a bad title. Instead of "People can't see things that are right in front of them," I should have titled it "People see things but don't pay attention to them," opting for precision even though it meant I couldn't use the idiomatic phrase can't see what's right in front of you. What made it worse is that I fell for the trap. I responded to the details instead of saying, "Whether your suggestion would have helped the user see the message or not is totally irrelevant to the point of the article.")

    I also hadn't predicted that my discussion of how reasonable people can disagree about how a setting should be exposed would turn into a discussion of how to shut down your computer, turning a footnote into the primary topic of discussion. But that's a fairly common occurrence: People focus on a side detail (which I added for color) and ignore the point of the story. Sometimes I think I'd be better off if I didn't give examples. That way nobody could be distracted by them.

Page 1 of 4 (35 items) 1234