• The Old New Thing

    The New Old New Thing

    This is the (future) new home of The Old New Thing. Just kicking the tires right now.
  • The Old New Thing

    Why does the copy dialog give me the incorrect total size of the files being copied?


    If you try to copy a bunch of files to a drive that doesn't have enough available space, you get an error message like this:

    1 Interrupted Action

    There is not enough space on Removable Disk (D:). You need an additional 1.50 GB to copy these files.

    ▭  Removable Disk (D:)
    Space free: 2.50 GB
    Total size: 14.9 GB
    Try again Cancel

    "But wait," you say. "I'm only copying 5GB of data. Why does it say Total size: 14.9 GB?"

    This is a case of information being presented out of context and resulting in mass confusion.

    Suppose you saw the information like this:

    ◢ Hard Disk Drives (1)   
    ▭  Windows (C:)
    Space free: 31.5 GB
    Total size: 118 GB
    ◢ Drives with Removable Storage (1)   
    ▭  Removable Disk (D:)
    Space free: 2.50 GB
    Total size: 14.9 GB

    In this presentation, it is clear that Total size refers to the total size of the drive itself.

    So the original dialog is not saying that the total size of data being copied is 14.49 GB. It's trying to say that the total size of the removable disk is 14.9 GB.

    Mind you, the presentation is very confusing since the information about the removable disk is presented without any introductory text. It's just plopped there on the dialog without so much as a hello.

    I'm not sure how I would fix this. Maybe reordering the text elements would help.

    1 Interrupted Action

    There is not enough space on Removable Disk (D:).

    ▭  Removable Disk (D:)
    Space free: 2.50 GB
    Total size: 14.9 GB

    You need an additional 1.50 GB to copy these files.

    Try again Cancel

    However, the design of the dialog may not allow the information tile to be inserted into the middle of the paragraph. It might be restricted to a layout where you can have text, followed by an information tile, followed by buttons. In that case, maybe it could go

    1 Interrupted Action

    You need an additional 1.50 GB to copy these files. There is not enough space on Removable Disk (D:).

    ▭  Removable Disk (D:)
    Space free: 2.50 GB
    Total size: 14.9 GB
    Try again Cancel

    But like I said, I'm not sure about this.

  • The Old New Thing

    The dangers of destroying a window while it is processing a sent message


    Commenter BryanK wonders why weird things happen if you destroy a window while it is processing the WM_ACTIVATEAPP message. He suspects that it's similar to the problems you encounter when you destroy a window in response to the WM_KILLFOCUS message.

    Although I haven't studied the WM_ACTIVATEAPP situation, I wouldn't be surprised if the problem is indeed entirely analogous. It just follows from general programming principles: After all, you are destroying the active window. The WM_ACTIVATEAPP message is sent as part of the activation change, and the documentation says that the message is sent "when a window belonging to a different application than the active window is about to be activated." Notice: "about to be" activated. That other window hasn't been activated yet; you're still the active window.

    Destroying the active window means that the window manager has to find a new active window. You're triggering an activation change while another activation change is in progress; no wonder things get all messed up.

    I am now going to make a gross generalization. There may be exceptions to this rule, but it's a good place to start: Destroying yourself is (generally speaking) not an acceptable response to a sent message. The code that sent you the message is doing so because it wants to ask you a question (if it cares about the return value) or because it's informing you of something that is happening right now as part of a larger operation. (After all, if the code didn't mind if you received the information after the fact, it would have posted the message instead of sent it.)

    And (generally speaking) it's bad form to perform an operation that changes a system's state while it's notifying you that that very state change is in progress. When the state change is in progress, the state is unstable. (If it were stable, then the state change would either not yet have begun or already have finished!)

  • The Old New Thing

    And now, your moment of reflection


    Master storyteller Ira Glass teaches us how to tell a story, and the importance of the moment of reflection. (In the third video he explains why when you are trying to do something creative you always suck, and that's okay.)

    And once you've soaked up Ira's advice, you can admire Kasper Hauser's parodies: Going Postal and Phantom High School.

  • The Old New Thing

    Signs that the symbols in your stack trace are wrong


    One of the things programmers send to each other when they are trying to collaborate on a debugging problem is stack traces. Usually something along the lines of "My program does X, then Y, then Z, and then it crashes. Here is a stack trace. Can you tell me what's wrong?"

    It helps if you at least glance at the stack trace before you send it, because there are often signs that the stack trace you're about to send is completely useless because the symbols are wrong. Here's an example:

    We are testing our program and it gradually grinds to a halt. When we connect a debugger, we find that all of our threads, no matter what they are doing, eventually wind up hung in kernel32!EnumResourceLanguagesA. Can someone explain why that function is hanging, and why it seems all roads lead to it?

       0  Id: 12a4.1468 Suspend: 1 Teb: 000006fb`fffdc000 Unfrozen
       1  Id: 12a4.1370 Suspend: 1 Teb: 000006fb`fffda000 Unfrozen
       2  Id: 12a4.1230 Suspend: 1 Teb: 000006fb`fffd8000 Unfrozen
       3  Id: 12a4.cc0 Suspend: 1 Teb: 000006fb`fffd6000 Unfrozen
      4  Id: 12a4.1208 Suspend: 1 Teb: 000006fb`fffd4000 Unfrozen
      5  Id: 12a4.1538 Suspend: 1 Teb: 000006fb`fffae000 Unfrozen
       6  Id: 12a4.16e0 Suspend: 1 Teb: 000006fb`fffac000 Unfrozen

    This stack trace looks suspicious for a variety of reasons.

    First of all, look at that offset EnumResourceLanguagesA+0xbea00. It's unlikely that the EnumResourceLanguagesA function (or any other function) is over 750KB in size, as this offset suggests.

    Second, it's unlikely that the EnumResourceLanguagesA function (or any other function, aside from obvious cases like tree walking) is recursive. And it's certainly unlikely that a huge function will also be recursive.

    Third, it seems unlikely that the EnumResourceLanguagesA function would call, NETAPI32!I_NetGetDCList. What does enumerating resource languages have to do with getting a DC list?

    Fourth, look at those functions that are allegedly callers of EnumResourceLanguagesA: bogosoft!CObjMarker::RequestBlockForFetch, bsnetlib!CSubsystem::CancelMain, bsnetlib!Tcp::ReadSync. Why would any of these functions want to enumerate resource languages?

    These symbols are obvious wrong. The huge offsets are present because the debugger has access only to exported functions, and it's merely showing you the name of the nearest symbol, even though it has nothing to do with the actual function. It's just using the nearest signpost it can come up with. It's like if somebody gave you directions to the movie theater like this: "Go to city hall downtown and then go north for 35 miles." This doesn't mean that the movie theater is in the downtown district or that the downtown district is 35 miles long. It's just that the person who's giving you directions can't come up with a better landmark than city hall.

    This is just another case of the principle that you have to know what's right before you can see what's wrong. If you have no experience with good stack traces, you don't know how to recognize a bad one.

    Oh, and even though the functions in question are in kernel32, you can still get symbols for that DLL with the help of the Microsoft Symbol Server.

  • The Old New Thing

    MessageBoxIndirect loads the icon itself; you can't hand it a pre-loaded icon


    Commenter 8 wants to know how to tell the MessageBoxIndirect function to use an existing HICON instead of pointing it to an icon resource.

    You can't.

    The MessageBoxIndirect loads the icon itself. You can't hand it a pre-loaded icon.

    Of course, it's hardly rocket science to write your own MessageBoxWithMyIcon function that lets you use whatever icon you want. There's no law that says all Yes/No dialogs must use the MessageBox function. Feel free to write your own.

    The MessageBox and MessageBoxIndirect functions are just convenience functions. They don't create new functionality; they don't do anything you couldn't already do yourself. You can have a template dialog box that you use for "generic" purposes and set the icon and text yourself. Or, if you're really adventuresome, you can generate a dialog template on the fly.

    The MessageBox and MessageBoxIndirect functions never aspired to be "everything anybody could ever do with a dialog box." They just provide some basic functionality that lots of people find useful. If you need more functionality, then you can always write it yourself. (There's already a function for "everything anybody could ever do with a standard Win32 dialog box": It's called, um, DialogBox.)

    Windows Vista introduces a considerably more customizable "message box"-type dialog known as a Task Dialog; you may want to give that one a try.

  • The Old New Thing

    Replaying input is not the same as reprocessing it


    Once upon a time, there was an application that received some input and said, "Okay, this input cancels my temporary state. I want to exit my temporary state, but I also want the input that took me out of the temporary state to go to whatever control would have received the input if I hadn't been in the temporary state in the first place." (For example, you might want the input that dismisses a pop-up window to be acted upon rather than eaten by the pop-up.) The application decided to solve this problem by regenerating the input message via Send­Input, so that it goes back into the input queue. The theory, is that when the message pump pulls the regenerated input out of the queue, the temporary state will not be present, and the message will be routed to the correct window.

    I raised concerns that this technique would create problems with input reordering and multiple-processing, but the customer decided to stick with their original design.

    Time passed, and I had forgotten about this application.

    Some months later, another question came in: "We find that when the system is under load, we sometimes get into a state where dismissing our temporary state results in the mouse button getting 'stuck' down. i.e., the user physically releases the mouse button, but we get spurious WM_LBUTTON­DOWN with no matching WM_LBUTTON­UP."

    The customer, it turns out, was the same one I had cautioned earlier about the dangers of replaying input.

    When you get input, that is your chance to process the input. If you decide you don't want to deal with the input right now and replay it via Send­Input, you create a few new problems:

    First, you've caused everybody else who is looking at input states to see a second copy of your replayed events. If it were a keyboard event you replayed, a keyboard hook (or any code which subclassed your window) would see a key go down twice. If there were any mouse hooks, they would see the button go down twice. This is particularly confusing because the mouse button doesn't autorepeat. How can it go Down two times in a row without an intervening Up?

    Second, if there is other input in your queue, you just rearranged input events. For example, suppose the input queue consists of the following events:


    You retrieve the first message (the button-down), resulting in the following input queue:


    For illustrative purposes, I crossed out the message that is no longer in the queue, so you can see where it used to be.

    Now you decide to replay that message via Send­Input. This appends the event to your queue, resulting in


    Your message pump runs, it processes the button-up event ("Huh? How did I get an Up without a Down?"), and then it processes the button-down event. There are no further events, so the mouse button is down and gets stuck that way.

    You can imagine what other sorts of bad things can happen if an event in the queue is, say, a press or release of the shift key. Oops, the user clicked the Delete button and then hit the shift key afterwards to type a capital letter A, but due to your input reordering, your code saw it as a Shift+Click on the Delete button, and the item was deleted without confirmation.

    When you get an input message, that is your chance to process it. If you decide that you want to hand the message off to somebody else, you have to do it during the processing of that message. If you try to process it at some other time, the input states may not be right.

  • The Old New Thing

    Why do I get notified for changes to HKEY_CLASSES_ROOT when nobody is writing to HKEY_CLASSES_ROOT?


    A customer had a question about the Reg­Notify­Change­Key­Value function.

    We are using it to monitor the HKEY_CLASSES_ROOT tree as follows:

        true, // monitor entire subtree
        true); // asynchronous mode

    If I understand the documentation correctly, this registers for notifications when subkeys are added, deleted, or when values are changed. However, it seems that my event becomes signaled at many other times, for example, when I switch folders in an Explorer window. I fired up Process Monitor and confirmed that nobody (not even Explorer) is writing to HKEY_CLASSES_ROOT.

    Why are we getting spurious notifications? Have we misunderstood what this function does?

    Everything is working as expected; it's just that your expectations are wrong.

    Recall that the HKEY_CLASSES_ROOT registry key is really a combined view of HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. Specifically, it is a combined view of HKEY_LOCAL_MACHINE\Software\Classes and HKEY_CURRENT_USER\Software\Classes. And HKEY_CURRENT_USER\Software\Classes is itself just an alias for HKEY_USERS\«SID»_Classes. Therefore, if you're going to look in Process Monitor, you need to be looking at all of those locations to see changes that eventually get reported as changes in HKEY_CLASSES_ROOT.

    In this particular case, Explorer was making changes to HKEY_USERS\«SID»_Classes\Local Settings, which shows up as HKEY_CLASSES_ROOT\Local Settings.

    Upon receiving this explanation, the customer understood what was going on, and also remarked that they were going to look to see if they could register their notification on a location that isn't quite so broad.

  • The Old New Thing

    What are the conventions for managing standard handles?


    Consider this function:

    void ChangeConsoleColor(WORD wColor)
     HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
     if (h != INVALID_HANDLE_VALUE) {
      SetConsoleTextAttribute(h, wColor);

    "When I call this function, it works the first time, but when I call it a second time, Get­Std­Handle returns a handle numerically identical to the one returned by the first call, but the handle is now invalid, presumably because I closed it. I closed it because I was taught to clean up after myself. Is this a case where I shouldn't?"

    Yes, you should clean up after yourself, but you should also have been taught to be respectful of community property. In this case, you walked into the TV room of your dormitory, watched an episode of Friends, and then smashed the television with a baseball bat. Later, you came back to the room to watch another episode of Friends and said, "Hey, what happened to our television?" (You can tell I'm old because I'm talking about the TV room of a dormitory.)

    The standard handle values are sort of like a global variable for your process. Anybody can call Get­Std­Handle to read the variable, and anybody can call Set­Std­Handle to set it. But as with any other global handle variable, you need to observe certain rules to ensure that the value is always valid.

    Suppose you had a global variable called HANDLE hSomeFile. What invariants would you want to apply?

    • If the value is INVALID_HANDLE_VALUE, then there is no active file. (You might also have decided to use NULL as your special value, but INVALID_HANDLE_VALUE works better here because that is the conventional sentinel value for file handles.)
    • If the value is not the special value above, then it refers to a valid file handle.

    That second invariant above already establishes a rule:

    • If you close the handle held in the global variable, you must also set the global variable to a new valid value.

    As I noted some time ago, programming is a game of stepping-stone from one island of consistency to another. You start with a consistent system, you perturb it (temporarily violating consistency), and then you re-establish consistency. Closing the handle makes the value invalid, so you need to follow up by making the value valid again. Otherwise you left your system in an inconsistent state.

    Okay, now instead of talking about that global variable hSomeFile, let's talk about the global handle hidden behind Get­Std­Handle and Set­Std­Handle. Congratulations, we just established the rules for managing standard handles.

    • If Get­Std­Handle returns INVALID_HANDLE_VALUE, then there is no active file.
    • If the value is not the special value above, then it refers to a valid file handle. (Note that file handles can refer to things that aren't files. In our case, it often will refer to a console.)
    • If you call Close­Handle on a standard handle, then you must also call Set­Std­Handle to set a new value for the standard handle.

    Note that these rules are just conventions. If you want to violate them by, say, closing the handle and then leaving a garbage handle in the hidden global variable for the next guy to trip over, then that's your problem. For example, you might choose to violate the rules temporarily, and then fix things up before anybody notices.

  • The Old New Thing

    Thanks for reminding me what to do when the elevator is out of order


    Every few years, the building maintenance people have to perform tests on the elevators to ensure they meet safety regulations. And the real estate department sends out the usual notice informing the building occupants that the elevators in the building will be taken out of service at various times during the day. They were kind enough to include the following advice:

    If an elevator is non-responsive and/or has out of order signage posted, please use another available elevator.

    One of my colleagues sarcastically remarked, "Wow, thank goodness they sent that email. I'd have no idea what to do had I seen a non-responsive elevator with an 'out of order' sign posted on it."

Page 372 of 464 (4,639 items) «370371372373374»