• The Old New Thing

    The voice of Carl Kasell emerges from the loudspeaker as some old guy stands there and moves his mouth

    • 4 Comments

    Some time ago, the NPR news quiz Wait Wait... Don't Tell Me taped a show in Seattle. (They're back in town tonight.) I was fortunate to score tickets to that show, in part because I ordered them nearly a full year before taping. Watching the taping of the show is quite a treat, and I recommend it for any fan of the program. You can watch Peter Sagal pace back and forth as he talks and contrast it to old-school radio man Carl Kasell, who stands perfectly still as he delivers his lines.

    The strangest part of the experience was putting the face to the voice. When Carl Kasell started talking, my reaction was, "Hey, I hear the voice of Carl Kasell, and that old guy on stage is doing a really good job of lip-synching."

    After the show, the on-air talent hung around on stage, and enthusiastic audience members approached the stage to chat, get autographs, and generally be adoring fans. Most of the talent hung around in a group at one end of the stage, but not Carl Kasell. He stood at the other end of the stage, because Carl is special. Whereas the others dealt with a small crowd, the people waiting to see Carl stood patiently in a line. And he also had a bodyguard to facilitate the process.

    You don't expect a public radio news announcer to have a security detail, but that's the level of fame Carl Kasell has risen to.

  • The Old New Thing

    How do I convert an ANSI string directly to UTF-8?

    • 19 Comments

    A customer asked the following question:

    Is there a way to convert an ANSI string directly to UTF-8 string? I have an ANSI string which was converted from Unicode based of the current code page. I need to convert this string to UTF-8.

    Currently I am converting the string from ANSI to Unicode (Multi­Byte­To­Wide­Char(CP_ACP)) and then converting the Unicode to UTF-8 (Wide­Char­To­Multi­byte(CP_UTF8)). Is there a way to do the conversion without the redundant conversion back to Unicode?

    There is no multibyte-to-multibyte conversion function built into Windows (as of this writing). To convert from one 8-bit encoding to another, you have to use Unicode as an intermediate step.

    Fortunately, one of my colleagues chose not to answer the question but instead responded to the question with another question:

    Is the data loss created by the initial conversion to ANSI really acceptable? Convert from the original Unicode string to UTF-8, and you avoid the potential mess introduced by the Unicode-to-ANSI conversion step.

    The customer was puzzled by this data loss remark:

    I'm using the same code page when converting from Unicode to ANSI as I am from converting from ANSI to Unicode. Will there still be a data loss?

    None of the code pages which Windows supports as an ANSI code page can express the full repertoire of Unicode characters. It's simple mathematics: Since one of the requirements for being an ANSI code page is that no single character can be more than 2 bytes, there simply isn't enough expressive power to encode all of Unicode. Now, if you're lucky, all of the characters you're encoding will exist in the ANSI code page, and they will survive the round trip, but that's just if you're lucky.

    It's like converting an image from 32-bit color to 8-bit color via the halftone palette. The palette is the "code page" for the conversion. Remembering to use the same palette when converting back is an essential step, but the result of the round trip will be a degraded image because you can't encode all 32-bit colors in a single 256-color palette. If you're lucky, all the colors in the original image will exist in your palette and the conversion will not result in loss of information, but you shouldn't count on being lucky.

    The customer went on to explain:

    Unfortunately, my code does not have access to the original Unicode string. It is a bridge between two interfaces, one that accepts an ANSI string, and another that accepts a UTF-8 string. I would have to create a new Unicode interface, and modify all existing callers to switch to the new one.

    If all the callers are generating Unicode strings and converting them to ANSI just to call the original ANSI-based interface, then creating a new Unicode-based interface might actually be a breath of fresh air. Keep the poorly-designed ANSI interface around for backward compatibility, so that callers could switch to the Unicode-based interface at their leisure.

    Bonus chatter: Even the round trip from ANSI to Unicode and back to ANSI can be lossy, depending on the flags you pass regarding use of precomposed characters, for example.

  • The Old New Thing

    The giant typewriter eraser in the Olympic Sculpture Park in Seattle

    • 21 Comments

    The Olympic Sculpture Park in Seattle is open and free to the public all year around. (And I'm surprised they haven't gotten the heat from the IOC over use of the word Olympic.)

    One of the works is a giant typewriter eraser. When my friend took her niece (I'm guessing around ten years old at the time) to visit the park, the girl asked, "What's that?"

    Oh, that's a typewriter eraser. Back before Wite-Out or eraser ribbons, this was how you corrected mistakes. This end is the eraser, and you use that end to brush the crumbs off.

    The next question was unexpected, but in retrospect, inevitable.

    "What's a typewriter?"

  • The Old New Thing

    Puzzle: Can you explain this program's crash profile?

    • 31 Comments

    Some time ago, I was asked to help a customer study a set of crashes that had been collected by Windows Error Reporting. (You too can sign up to obtain access to crash data for your application.) The issue itself was the 325th most common crash in the ISV crash database, so fixing it would mean a lot toward improving the overall perceived stability of Windows. Fortunately, the issue was resolved relatively easily, but that's not what made the story interesting. What I found interesting was a little puzzle that faced me when I called up their crash profile.

    One of the items in the crash profile report is a histogram plotting how many crashes per day were reported over the past three months. Most crash profiles take the form of an erratic graph with random day-to-day fluctuations. Sometimes you'll see a gradual trend (for example, as more and more people upgrade to a newer version). But this one had a strong pattern:

    The number of crashes per day remains high for several days, and then plummet for two days, then return to their high values, repeating on a regular cycle.

    It took me a bit of thought, but soon I understood why. Perhaps you can figure it out, too. Hints after the break.

    If you actually stop and count (I didn't; I just eyeballed it), there are five days with high crash frequency, followed by two days with low crash frequency.

    What happens on a seven-day cycle?

    The five days with high crash frequency correspond to Monday through Friday; the two days with low crash frequency correspond to Saturday and Sunday.

    The program in question targets a business audience. People use the program when they're at work (during the work week), but they don't use the program when they're at home (on the weekend). A program that isn't running can't crash.

  • The Old New Thing

    Why doesn't the Windows Vista copy progress dialog show the names of the files being copied?, redux

    • 45 Comments

    As expected, everybody concluded that the Windows Vista copy progress dialog made every wrong decision possible. Let's look at some of the suggestions on making it suck less:

    Why not update the file name every five seconds to the file that is being copied at that time?

    Sure, you could do that, but the cost of getting the name is part of the problem. Retrieving the name is more than just "Remove everything after the last dot." You may have to look up localization information in order to display the name of the item in a manner appropriate for the user's preferred language. Since the operation being performed might be destructive (for example, delete or move), you need to retrieve the display name before you begin the operation. Since Microsoft Research hasn't yet finished their project to predict the future, we don't know at the time an operation starts whether it will take more than five seconds. Therefore, we have to play it safe and retrieve the name just in case. All you saved was the cost of the screen update; you didn't save the cost of retrieving the display names.

    That said, in Windows 7, when you expand the file copy progress dialog, it updates the fields at a maximum speed of four times per second. This is probably a decent balance between not updating faster than the screen refresh rate while still updating fast enough that you don't get the impression that it's skipping some files.

    Obviously the solution is to make getting localised names faster.

    Yup, work was done to make getting localized names faster. When the copy engine begins operating on a directory, it caches all the localized names at one go and reads the names out of the cache as it processes the directory.

    The reason 'updating the display is slow' is nonsense, as the progress bar is constantly updating anyway.

    I think Drak didn't click through the discussion of how updating the screen can be a significant cost when you are updating continuously. The operative word here is continuously. If you're copying a lot of small files, and you redraw each time you get to a new file, you may end up redrawing hundreds of times a second. On the other hand, the progress bar updates only around ten times a second, and the copy rate only once a second, and neither have to access the disk to decide what to display next. A changing progress bar or updating copy estimate does not come across as unstable; they appear as progress. But a hundred file names flying past per second? That looks unstable.

    Is it really necessary to display those names localized? Most users will never see them, and it'll confuse many of those that do see them.

    Imagine if you clicked to delete the file Calculator.lnk and the dialog box said "Deleting 計算器.lnk". Would you be concerned?

    It's only confusing if you sometimes see the nonlocalized names, like from programs which just assume that the display name can be obtained by deleting everything after the last dot instead of using the SHGetFileInfo function. But Apple has the same problem, and everybody knows that Apple does everything right.

    It took me a while to realize that the complaint about disk-to-disk copy of several large files at once referred not to selecting multiple files and copying them in a single operation but rather starting one copy, then starting another copy, then starting another copy. If you copy them as a single operation, then they will queue up behind each other. But if you copy them as separate operations, then they will all compete with each other. The proposal to have a single queue for files copied to/from the same disk sounds interesting, but it quickly gets complicated:

    • Suppose there is a copy in progress from volume A to volume B, and another copy from volume B to volume C, and another copy from volume D to itself. Presumably, the second copy should wait behind the first (since they both involve volume B); should the third copy "jump the queue" and start immediately?
    • Is the queue implicit or explicit? In other words, is there a single dialog with a list box, one entry per queued-up operation? Or do you still keep separate dialog boxes, but just have the second dialog box wait until the first one is finished before it starts its operation? If you think about it, you can't have a single dialog with a list box: Suppose a program calls SHFileOperation, and its operation gets queued up. You disable the application window and do... what? Do you set focus to the queue dialog? That queue dialog is part of some other window hierarchy, so it can get stuck behind the caller's window. And even if you make sure it comes to the foreground (hooray for focus-stealing), you then have the problem that when the operation completes, focus goes to the queue dialog's owner, not to the program that triggered the focus change.
    • Suppose I start copying a large file from volume A to volume B, and then a colleague asks, "Hey, can you copy that shortcut to volume B so I can take a look at it?" Under the old system, you would start a second copy operation, and it would run concurrently with the first copy operation but complete first (since shortcuts are relatively small). With the queueing design, you would need a way to let people adjust the priority of jobs in the queue so the second one could be bumped ahead of the first. Which also means that when a partially-completed operation gets pushed down the queue, you need to be able to pause the operation and resume it later. This is a lot of UI to design, implement, and test, especially since we already decided that you can't have a single dialog box with a list box.
    • When the second operation queues up behind the first, its total estimated time needs to include the estimated times for all the jobs ahead of it in the queue. How do you get an estimate for a job that hasn't started yet? Do you do some preliminary calculations to come up with the estimate? But wait, that's going to access the hard drive and interfere with the first operation. Even if you have only one job ahead of you in the queue (and therefore have an estimate for that job), it means that copying a 1KB file might tell you "Estimated time to completion: 30 minutes" because it's waiting behind a 4GB file.

    I'm not saying that these problems are unsolveable. But the simple suggestion of using a queue created a very large new problem. As we saw last time, you can't solve every problem; you have to decide which twenty problems you're going to solve and leave the others for next time.

    Windows 7 decided to address the problem by letting you trade off performance for information. The operation defaults to performance (no file name updates), but you can expand the dialog to say, "I'm willing for my file operation to be a smidge slower in exchange for more information about how it's going."

    I wonder if there are people would be willing to make the tradeoff "I'm willing to lose the progress bar in exchange for not having to wait for the operation to start while it calculates how big the progress bar should be." But I guess those people just use xcopy.

    At any rate, the issue of the missing file names was fixed in Windows 7, so any further complaining just falls into the category of asking for a time machine. Though I did find it interesting that people suggested solutions that involved doing more work. Doing more work means writing more code, which means designing and testing more code, which means the product ships even later. I bet these are also the same people who complain that Windows always ships late. (What ever happened to the commenters who say that Microsoft should be deleting code more aggressively? Oh, wait, I know what happened to them. "Microsoft should be deleting code, but only the code for for features that I personally don't like." Good luck getting people to agree on what code to delete. It's like the people who argue that Microsoft should intentionally abandon backward compatibility, then change their tune when they realize that their favorite program stopped working.)

  • The Old New Thing

    Welcome to the maze and enjoy the Habitrail

    • 1 Comments

    Last year, Microsoft Press and Microsoft Learning moved to new buildings in downtown Bellevue, bidding good-bye to The Maze. This was a nickname for their former building I had been unfamiliar with, but not having been to their building, I can't say whether the name is deserved or not.

    What I do know, however, is that the small cluster of buildings they moved from are connected by enclosed walkways, which are nicknamed the Habitrail due to their startling similarity to the hamster transportation tubes. Back in the old days, these corridors were lined with stand-up arcade consoles, owned by the people who work in the buildings, and placed there for anybody to stop by and unwind with a game of Star Wars or Asteroids or some other classic arcade game.

    Alas, the impromptu arcade game center had to be shut down when the building safety people determined that it posed a fire safety hazard. (I suspect that the reason was not only that the machines were powered by daisy-chained extension cords, but also that safety rules required that the corridor remain clear of obstacles at all times.)

  • The Old New Thing

    That's a great idea, it's on the list

    • 38 Comments

    The great thing about the taskbar is that everybody and their pet dog have an idea for how it can be improved.

    The bad thing about the taskbar is that everybody and their pet dog have an idea for how it can be improved. (And everybody and their pet dog also think that their feature suggestion is the important one that should be worked on next. Especially if it's "just a tiny little feature.")

    For a few years, my office sat across the hall from the person responsible for the taskbar design and features. To help manage all the wonderful ideas that came in, my colleague maintained a spreadsheet of all suggestions that were submitted and deemed worthy of further investigation. And for each suggestion, there was a rough estimate of how much developer time it would take to implement that feature.

    The total came out to over 200 days of idealized developer time.

    In other words, under perfect conditions (for example, on the rosy assumptions that no earlier feature made a subsequent feature more complicated and that all the code will work the first time), it would take one person over 40 weeks of vacation-free full-time coding to implement all the little features people requested. Death by a thousand cuts. Or in this case, 200 cuts.

    That calculation of course ignores the time spent designing the feature, developing a test plan, running it through usability tests, writing the automated testing, debugging all the issues that arise, doing the threat modeling, fixing the compatibility issues from applications that relied on the old behavior, and all the other things that you have to do to ship a feature beyond simply writing the code for it. (Indeed, the "write the code" step is one of the smallest steps in the product development cycle!)

    Obviously, you can't implement everything on the list: You don't know what you do until you know what you don't do. (And imagine the size of the resulting taskbar configuration dialog!) But it also means that there are a lot of people with pet dogs who think you're an idiot.

    Maintaining the list was a useful exercise for another reason: Whenever anybody stopped by and said, "Hey, why doesn't the taskbar...", my colleague could say, "That's a great idea. It's on the list."

    When my colleague left the group, ownership of the list was transferred to the next person responsible for the taskbar design. For all I know, there's still a list sitting in a spreadsheet on a designer's computer somewhere.

    Part of the hard job of product design is deciding which 20 features you have the resources to pursue and which 180 to leave for next time. If you choose the right 20, people will say you're the best new UI feature in Windows, or even the best Windows 7 feature, and they won't mind too much that you didn't get to the other 180.

  • The Old New Thing

    How do I accept files to be opened via IDropTarget instead of on the command line? - bonus content

    • 17 Comments

    One of my colleagues tipped me off to some additional resources on the subject of using the DropTarget technique for accepting files for execution.

    First, it turns out that there is an SDK sample that demonstrates the DropTarget technique after all. This sample is fifteen years late according to one commenter who apparently thinks that the Platform SDK needs to provide a sample for a feature that won't be invented for another twelve years. Maybe we can use the Microsoft Research project to predict the future. No wait, we also need to get them to invent the time machine so we can take the future-predictor machine back in time 15 years.

    Second, there is a sample for the ExecuteCommand technique. The ExecuteCommand technique is preferred over the DropTarget technique because it is much easier to implement. (Translation: much less you can get wrong.) Like the DropTarget technique, the ExecuteCommand supports out-of-process activation.

    And third, as it turns out, App Path registration supports HKEY_CURRENT_USER after all, thereby addressing one of the complaints raised by a commenter (a complaint I answered incorrectly).

  • The Old New Thing

    Every window with the WS_SYSMENU style has a system menu, but it's not there until it needs to be

    • 5 Comments

    I mentioned last time that there's an optimization in the treatment of the system menu which significantly reduces the number of menus in the system.

    When a window has the WS_SYSMENU window style, it has a system menu, but until somebody calls Get­System­Menu on that window, nobody knows what its menu handle is. Until that point, the window manager doesn't actually have to commit to creating a menu for the window; it can just pretend that the window has one. (This technique goes by the fancy name lazy initialization.)

    The window manager creates a global default system menu which contains the standard system menu items. If somebody presses Alt+Space or otherwise calls up the system menu for a window that has never had Get­System­Menu called on it, the window manager just uses the global default system menu, since it knows that nobody has customized the menu. (You can't customize a menu you don't have the handle to!) Since most people never customize their system menu, this optimization avoids cluttering the desktop heap with identical copies of the same menu. This was a particularly important optimization back in the 16-bit days, when all window manager objects had to fit into a single 64KB heap (known as System Resources).

    If you are really sneaky, you can catch a glimpse of the elusive global default system menu as it whizzes by: As with any other popup menu, the handle to the menu being displayed is passed to your window's WM_INIT­MENU­POPUP, and if your program has never called Get­System­Menu, the handle that you will see is the global default system menu. Mind you, you can't do much to this menu, since the window manager blocks any attempt to modify it. (Otherwise, your program's menu modification would have an unintended effect on the menus of other programs!)

    Therefore, if your program is in the habit of modifying its system menu in its WM_INIT­MENU­POPUP handler, you should stick a dummy call to Get­System­Menu in your WM_CREATE handler to force your system menu to change from a pretend system menu to a real one.

  • The Old New Thing

    When will the window manager destroy a menu automatically, and when do I need to do it manually?

    • 17 Comments

    Our old friend Norman Diamond wonders when you are supposed to destroy a menu and when you are supposed to let Windows destroy it.

    The rules for when the window manager implicitly destroys menus are actually not that complicated.

    • If a window is destroyed, the menus attached to the window are also destroyed:
      • Attached as the menu bar (Get­Menu/Set­Menu)
      • Attached as the system menu (Get­System­Menu)
    • If a menu is destroyed, its submenus are also destroyed.
    • If you replace a MIIM_SUBMENU submenu, the old menu is destroyed.
    • If you pass bRevert = TRUE to Get­System­Menu, then the old system menu is destroyed and a clean system menu is created in its place.

    Outside of the above situations, you are on your own.

    Of course, when I write that "you are on your own" I do not mean that "every code which sees a menu is responsible for destroying it." If that were the case, you would have a disaster as the slightest passing breeze would cause people to call Destroy­Menu all over the place. Rather, I mean that in all other cases, you need to "work it out amongst yourselves" who is responsible for destroying the menu. Typically, the person who creates the menu takes responsibility for destroying it, although that responsibility can be handed off based on mutual agreement between the creator and another component.

    The original question did include a misunderstanding:

    If the old object belonged to a window class, and we destroy the old object, how do we know that other windows of the same class aren't going to get in trouble?

    The mistaken belief here is that each window of a class shares the same menu. If that were true, then if a program created two windows of the same class, modifications to one window's menu would affect the other. You can see that this is not true by inspection, or at least it was easier back in 1995. On Windows 95, open two Explorer windows, and set them into different views. The two windows now have different menus: One of them has a bullet next to the Large Icons menu item, whereas the other has a bullet next to Details.

    When you register a window class, you pass in the menu you want, but only in the form of a template:

        WNDCLASS wc;
        ...
        wc.lpszMenuName = MAKEINTRESOURCE(...);
    

    There is no menu yet, just a description of how to create a menu when the time comes. When you create a window from this class, the window manager initializes the menu by doing the equivalent of

        SetMenu(hwnd, LoadMenu(pWndClass->hInstance,
                               pWndClass->lpszMenuName));
    

    Each window gets a fresh menu from the specified menu template. Once that's done, you can change it all you want; it won't affect any the menus associated with any other windows.

    The system menu works the same way: Every window starts out with a default system menu, and when you call Get­System­Menu with bRevert = FALSE, you get a handle to that system menu, which you can modify to your heart's content without affecting any other menus. System menus have this additional wrinkle where you can pass with bRevert = TRUE to ask the window manager to destroy the current system menu and replace it with a fresh new default system menu.

    Exercise: How would you accomplish the logical equivalent of Get­System­Menu(TRUE) for the menu bar menu?

    Bonus chatter: While the system menu certainly behaves as I described it above, there's actually a little bit of optimization going on under the hood. We'll look at that next time.

Page 127 of 419 (4,182 items) «125126127128129»