• The Old New Thing

    Spider Solitaire unseats the reigning champion

    • 38 Comments

    A few months ago, the usability research team summarized some statistics they had been collecting on the subject of what people spend most of their time doing on the computer at home. Not surprisingly, surfing the Internet was number one. Number two was playing games, and in particular, I found it notable that the number one game is no longer Klondike Solitaire (known to most Windows users as just plain "Solitaire").

    That title now belongs to Spider Solitaire. The top three games (Spider Solitaire, Klondike Solitaire, and Freecell) together account for more than half of all game-playing time.

    Personally, I'm a Freecell player.

    Exercise: Why aren't games like Unreal Tournament or The Sims in the top three?

  • The Old New Thing

    Precision is not the same as accuracy

    • 44 Comments

    Accuracy is how close you are to the correct answer; precision is how much resolution you have for that answer.

    Suppose you ask me, "What time is it?"

    I look up at the sun, consider for a moment, and reply, "It is 10:35am and 22.131 seconds."

    I gave you a very precise answer, but not a very accurate one.

    Meanwhile, you look at your watch, one of those fashionable watches with notches only at 3, 6, 9 and 12. You furrow your brow briefly and decide, "It is around 10:05." Your answer is more accurate than mine, though less precise.

    Now let's apply that distinction to some of the time-related functions in Windows.

    The GetTickCount function has a precision of one millisecond, but its accuracy is typically much worse, dependent on your timer tick rate, typically 10ms to 55ms. The GetSystemTimeAsFileTime function looks even more impressive with its 100-nanosecond precision, but its accuracy is not necessarily any better than that of GetTickCount.

    If you're looking for high accuracy, then you'd be better off playing around with the QueryPerformanceCounter function. You have to make some tradeoffs, however. For one, the precision of the result is variable; you need to call the QueryPerformanceFrequency function to see what the precision is. Another tradeoff is that the higher accuracy of QueryPerformanceCounter can be slower to obtain.

    What QueryPerformanceCounter actually does is up to the HAL (with some help from ACPI). The performance folks tell me that, in the worst case, you might get it from the rollover interrupt on the programmable interrupt timer. This in turn may require a PCI transaction, which is not exactly the fastest thing in the world. It's better than GetTickCount, but it's not going to win any speed contests. In the best case, the HAL may conclude that the RDTSC counter runs at a constant frequency, so it uses that instead. Things are particularly exciting on multiprocessor machines, where you also have to make sure that the values returned from RDTSC on each processor are consistent with each other! And then, for good measure, throw in a handful of workarounds for known buggy hardware.

  • The Old New Thing

    More undocumented behavior and the people who rely on it: Output buffers

    • 42 Comments

    For functions that return data, the contents of the output buffer if the function fails are typically left unspecified. If the function fails, callers should assume nothing about the contents.

    But that doesn't stop them from assuming it anyway.

    I was reminded of this topic after reading Michael Kaplan's story of one customer who wanted the output buffer contents to be defined even on failure. The reason the buffer is left untouched is because many programs assume that the buffer is unchanged on failure, even though there is no documentation supporting this behavior.

    Here's one example of code I've seen (reconstructed) that relies on the output buffer being left unchanged:

    HKEY hk = hkFallback;
    RegOpenKeyEx(..., &hk);
    RegQueryValue(hk, ...);
    if (hk != hkFallback) RegCloseKey(hk);
    

    This code fragment starts out with a fallback key then tries to open a "better" key, assuming that if the open fails, the contents of the hk variable will be left unchanged and therefore will continue to have the original fallback value. This behavior is not guaranteed by the specification for the RegOpenKeyEx function, but that doesn't stop people from relying on it anyway.

    Here's another example from actual shipping code. Observe that the CRegistry::Restore method is documented as "If the specified key does not exist, the value of 'Value' is unchanged." (Let's ignore for now that the documentation uses registry terminology incorrectly; the parameter specified is a value name, not a key name.) If you look at what the code actually does, it loads the buffer with the original value of "Value", then calls the RegQueryValueEx function twice and ignores the return value both times! The real work happens in the CRegistry::RestoreDWORD function. At the first call, observe that it initializes the type variable, then calls the RegQueryValueEx function and assumes that it does not modify the &type parameter on failure. Next, it calls the RegQueryValueEx function a second time, this time assuming that the output buffer &Value remains unchanged in the event of failure, because that's what CRegistry::Restore expects.

    I don't mean to pick on that code sample. It was merely a convenient example of the sorts of abuses that Win32 needs to sustain on a regular basis for the sake of compatibility. Because, after all, people buy computers in order to run programs on them.

    One significant exception to the "output buffers are undefined on failure" rule is output buffers returned by COM interface methods. COM rules are that output buffers are always initialized, even on failure. This is necessary to ensure that the marshaller doesn't crash. For example, the last parameter to the IUnknown::QueryInterface method must be set to NULL on failure.

  • The Old New Thing

    Hoping the worst-case scenario doesn't come to pass

    • 15 Comments

    A few years ago, NPR and American RadioWorks ran a story on the consequences to New Orleans of a Category 5 hurricane [NPR part 1] [NPR part 2]. I had been hoping that the city would escape the worst-case scenario of the water topping the levees and submerging the city in twenty feet of water, but yesterday's levee breaches appear to have taken us one step closer...

    As you probably know, I'm fascinated by language, particularly the slang terms of various professions, such as the rich acronym soup of the emergency medical field (my sick favorite being "CTD"). In the hurricane story, we hear the director of emergency management use the acronym KYAGB, which stands for "Kiss your..."

  • The Old New Thing

    Understanding hash codes

    • 23 Comments

    On more than one occasion, I've seen someone ask a question like this:

    I have some procedure that generates strings dynamically, and I want a formula that takes a string and produces a small unique identifer for that string (a hash code), such that two identical strings have the same identifier, and that if two strings are different, then they will have different identifiers. I tried String.GetHashCode(), but there were occasional collisions. Is there a way to generate a hash code that guarantees uniqueness?

    If you can restrict the domain of the strings you're hashing, you can sometimes squeak out uniqueness. For example, if the domain is a finite set, you can develop a so-called perfect hash which guarantees no collisions among the domain strings.

    In the general case, where you do not know what strings you are going to be hashing, this is not possible. Suppose your hash code is a 32-bit value. This means that there are 232 possible hash values. But there are more than 232 possible strings. Therefore, by the pigeonhole principle, there must exist at least two strings with the same hash code.

    One little-known fact about the pigeonhole principle is that it has nothing to do with pigeons. The term "pigeonhole" refers to a small compartment in a desk into which items such as papers or letters are distributed. (Hence the verb "to pigeonhole": To assign a category, often based on gross generalization.) The pigeonhole principle, then, refers to the process of sorting papers into pigeonholes, and not the nesting habits of members of the family Columbidae.

  • The Old New Thing

    On the adult appeal of dodgeball

    • 7 Comments

    NPR's Only a Game recently covered the rise of adult dodgeball. At MSN's tenth birthday party last week, there was a wide variety of entertainment options, the highlight of which appeared to be an organized dodgeball tournament. It was very well attended and didn't have the ego-damaging overtones you got from elementary school. A good time was had by all.

    The Senior Vice President of MSN happens also to have been the development manager of Windows 95, so he made the generous gesture of inviting the members of the Windows 95 team to his group's birthday party. (Since the remaining members of the Windows 95 team are outnumbered forty-to-one by the current members of the MSN team, it gave the impression that Windows 95 was merely an after-thought to MSN! "Ten years ago, MSN 1.0 went live! And if I recall correctly, some little operating system rode our coattails.")

  • The Old New Thing

    Program names in file type handlers need to be fully-qualified

    • 29 Comments

    Most people probably haven't noticed this, but there was a change to the requirements for file type handlers that arrived with Windows XP SP 2: Paths to programs now must be fully-qualified if they reside in a directory outside of the Windows directory and the System directory.

    The reason for this is security with a touch of predictability thrown in.

    Security, because one of the places that the SearchPath function searches is the current directory, and it searches the current directory before searching standard system directories or the PATH. This means that somebody can attack you by creating a file like say "Super secret information.txt" and creating a hidden NOTEPAD.EXE file in the same directory. The victim says, "Oh wow, look, super secret information, let me see what it is," and when they double-click it, the trojan NOTEPAD.EXE is run instead of the one in the Windows directory. Requiring paths to be fully-qualified removes the current directory attack.

    Predictability, because the contents of the PATH environment variable can vary from process to process. Consequently, the relative path could resolve to different programs depending on who is asking. This in turn results in having to troubleshoot problems like "It works when I double-click it from Explorer, but not if I run it from a batch file."

  • The Old New Thing

    What program did you get, Danny?

    • 0 Comments

    Danny Glasser remembers what program he got out of the back of a pick-up truck.

  • The Old New Thing

    Why is the default console codepage called "OEM"?

    • 7 Comments

    Last year, we learned that the ANSI code page isn't actually ANSI. Indeed, the OEM code page isn't actually OEM either.

    Back in the days of MS-DOS, there was only one code page, namely, the code page that was provided by the original equipment manufacturer in the form of glyphs embedded in the character generator on the video card. When Windows came along, the so-called ANSI code page was introduced and the name "OEM" was used to refer to the MS-DOS code page. Michael Kaplan went into more detail earlier this year on the ANSI/OEM split.

    Over the years, Windows has relied less and less on the character generator embedded in the video card, to the point where the term "OEM character set" no longer has anything to do with the original equipment manufacturer. It is just a convenient term to refer to "the character set used by MS-DOS and console programs." Indeed, if you take a machine running US-English Windows (OEM code page 437) and install, say, Japanese Windows, then when you boot into Japanese Windows, you'll find that you now have an OEM code page of 932.

  • The Old New Thing

    Free bicycles to borrow at Marymoor Park

    • 7 Comments

    Marymoor Park just keeps getting better.

    Just this year, they added a little Subway sandwich shop, so you don't even have to pack for a picnic in the park. Next, free Wi-Fi (sponsored by MSN). Then movies in the park (sponsored by First Tech Credit Union).

    The latest addition is free bicycles (sponsored by Dasani). Show a photo ID and you get a cardkey that gives you access to one-speed coaster-brake bicycles you can borrow for the day.

Page 361 of 448 (4,472 items) «359360361362363»