• The Old New Thing

    If you had to deal with preschoolers all day, you'd need a nap too


    Today, I'm turning it around: This is a dream that one of my friends had about me!

    She dreamed that she took her camera to school to take some pictures, possibly for the yearbook. She was somewhat surprised to discover that I was the new preschool teacher. When she popped in to my classroom to get a couple of pictures of me, she wasn't able to take any: Apparently, my new position was so exhausting that I'd had to take a nap on the king-size classroom bed...

  • The Old New Thing

    PLAY! A Video Game Symphony comes to Seattle


    Competing with the Miss America pageant for your Saturday evening attention is the Seattle performance of PLAY! A Video Game Symphony, featuring music from a large number of video games. Presumably, the music will have something to do with the accompanying video being projected on large screens.

    The description of the concert omits any mention of whether this is a cosplay event. Just saying.

  • The Old New Thing

    Yet another experiment in motivating people to find and fix bugs


    Everybody has probably heard about some project where management decided to motivate testers and programmers by rewarding testers for finding bugs and programmers for fixing them. In the absence of high ethical standards, this can devolve into the situation known to Dilbert fans as I'm gonna write me a new minivan.

    I experimented with this idea once, over a decade ago. Well, not exactly this idea, but a variation of it: For each bug in my code which I fixed, I paid the tester who found it.

    The risk here would be that I would intentionally resolve bugs as INVALID (or WONTFIX or anything other than FIXED) in order to avoid paying the penalty for fixing them, but I like to think that I made my decisions on their technical merits rather than based on my pocketbook. Since the tester saw the bug resolution, there was a degree of oversight: If I used bogus bug resolutions to avoid the bug fixing penalty, the tester would just reopen the bugs. The amount of the reward varied based on the quality of the bug, so that encouraged testers to focus on finding good bugs instead of weenie ones.

    I think I paid out a few dozen bug rewards. (It was a small project.)

  • The Old New Thing

    How do I launch the Explorer Search window with specific search criteria?


    A customer wanted to know how to launch Explorer's Search window with specific fixed search criteria. It turns out that there are two ways of doing this, the poor man's way and the overachiever's way.

    The overachiever's way is actually easier to discover. You can use the search-ms protocol to generate a command string that describes the query you want to perform and pass it to Shell­Execute.

    The poor man's way actually requires a little bit of out-of-the-box thinking: Open the Explorer Search window and interactively create the query you want to be able to relaunch later. Now do File, Save Search, and save the query. When you want to relaunch the query, execute the saved search. This is, after all, how end users save and re-use searches.

  • The Old New Thing

    Why does my window style change when I call SetWindowText?


    A customer observed some strange behavior with window styles:

    We ran some weird behavior: Calling the Set­Window­Text function causes a change in window styles. Specifically, calling Set­Window­Text results in the WM_STYLE­CHANGING and WM_STYLE­CHANGED messages, and sometimes the result is that the WS_TAB­STOP style is removed. Is this a bug? What would cause this?

    The Set­Window­Text message sends the WM_SET­TEXT message to the control, at which point anything that happens is the window's own responsibility. If it wants to change styles based on the text you sent, then that's what happens. The window manager doesn't do anything special to force it to happen or to prevent it.

    That's weird, because I'm not even listening for WM_SET­TEXT messages. I also verified that there is no call into my code during the call to the the Set­Window­Text function.

    I'm assuming that the window belongs to the same process as the caller. If the window belongs to another process, then the rules are different.

    I'm changing the text of a window created by the same thread.

    Okay, so let's see what we have so far. The customer is calling the Set­Window­Text function to change the text of a window created on the same thread. There is no handler for the WM_SET­TEXT message, and yet the window style is changing. At this point, you might start looking for more obscure sources for the problem, like say a global hook of some sort. While I considered the possibilities, the customer added,

    It may be worth noting that I'm using the Sys­Link.

    Okay, now things are starting to make sense, and it didn't help that the customer provided misleading information in the description of the problem. For example, when the customer wrote, "There is no handler for the WM_SET­TEXT message," the customer was not referring to the window whose window text is changing but to some other unrelated window.

    It's like responding to the statement "A confirmation letter should have been sent to the account holder" with "I never got the confirmation letter," and then the person spends another day trying to figure out why the confirmation letter was never sent before you casually mention, "Oh, I'm not the account holder."

    The WM_SET­TEXT message is sent to the window you passed to Set­Window­Text; in this case, it's the Sys­Link window. It is therefore the window procedure of the Sys­Link window that is relevant here.

    The Sys­Link control remembers whether it was originally created with the WS_TAB­STOP, and if the markup it is given has no tab stops, then it removes the style; if the markup has tab stops, then it re-adds the style.

    How do I add a tab stop to a string? I couldn't find any reference to it and all my guesses failed.

    The tab stops in question are the hyperlinks you added when you used the <A>...</A> notation. If the text has no hyperlinks, then the control removes the WS_TAB­STOP style because it is no longer something you can tab to.

  • The Old New Thing

    Each time I move, my mailbox moves further away


    When I was growing up, the mailman letter carrier came right to our front door. The mailbox was mounted on the front of the house right next to the front door. You could check the mail without even getting dressed; just open the door a crack and stick out your hand. Approximate distance from front door to mailbox: less than 1 foot.

    In the next house I lived in, the mailbox was no longer mounted on the house. Instead, it stood at the end of the driveway. Approximate distance from front door to mailbox: 55 feet.

    My next house was in a neighborhood which grouped its mailboxes in clusters. The cluster of about eight mailboxes which served my house (and my immediate neighbors) was two houses down from mine. Approximate distance from front door to mailbox: 120 feet.

    My current house is in a small neighborhood which groups all the mailboxes together into a single cluster. The mailbox cluster is at the entrance to the neighborhood, approximately 540 feet from my front door.

    This is why I have time to read junk mail. I need to pass the time on the way back from the mailbox.

    Bonus chatter: Since I moved, I have to go through the whole process of opting out of phone book delivery once again.

  • The Old New Thing

    Please hold your head perfectly still while you write up that memo


    I dreamed that the original Volkswagen Beetle factory was so cramped that the office workers had to move their desks to the factory floor, with heavy equipment swinging around just inches from their faces. To prevent serious injuries, a template passed through every so often to make sure nothing was out of place.

  • The Old New Thing

    There is no complete list of all notifications balloon tips in Windows


    A customer wanted a complete list of all notifications balloon tips in Windows.

    There is no such list. Each component is responsible for its own balloon tips and is not required to submit their list of balloon tips to any central authority for cataloging. In order to create such a list, somebody would have to go contact every component team and ask them for a list of all their balloon tips, and that component team would probably undertake a search of their code base looking for balloon tips. And figuring out the text of each balloon tip can be tricky since the text may be built dynamically. (And the customer didn't ask for an explanation of the conditions under which each balloon tip may appear, but that's probably going to be their follow-up question.)

    It's like publishing instructions on how to display a message on the message board, and then somebody asking the message board manufacturer, "Please send me a list of all messages that might appear on the message board." The message board manufacturer doesn't know how its customers are using the message board. They would have to go survey their customers and ask each one to build an inventory of every message that could potentially be shown.

    In other words, this customer was asking for a research project to be spun up to answer their question.

    I suspected that this was a case of the for-if antipattern being applied to custom support questions, and I asked what the customer intended to do with this information.

    It turns out that they didn't even want this list of balloon tips. They just had a couple of balloon tips they were interested in, and they wanted to know if there were settings to disable them.

    But even though that was their stated goal, they still reiterated their request for a list of balloon tips. The customer liaison asked, "Is there a possibility is getting a list of balloon tips generated by Windows itself? Even a partial list would be helpful. Can we help with this?"

    What the customer liaison can do is contact each Windows component team and ask them, "Can you give me a list of the balloon tips your component generates? Even a partial list would be helpful." I wished him luck.

    The customer liaison replied, "I passed this information to the customer and will follow up if they have any further questions." No follow-up ever appeared.

  • The Old New Thing

    I got an array with plenty of nuthin'


    A customer reported a memory leak in the function PropVariantClear:

    We found the following memory leak in the function PropVariantClear. Please fix it immediately because it causes our program to run out of memory.

    If the PROPVARIANT's type is VT_ARRAY, then the corresponding SAFEARRAY is leaked and not cleaned up.

    SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
    v.vt = VT_ARRAY;
    v.parray = psa;
    // The psa is leaked

    Right now, we are temporarily working around this in our program by inserting code before all calls to PropVariantClear to free the SAFEARRAY, but this is clearly an unsatisfactory solution because it will merely result in double-free bugs once you fix the bug. Please give this defect your highest priority as it is holding up deployment of our system.

    The VT_ARRAY value is not a variant type in and of itself; it is a type modifier. There are other type modifiers, such as VT_VECTOR and VT_BYREF. The thing about modifiers is that they need to modify something.

    The line v.vt = VT_ARRAY is incorrect. You have to say what you have a safe array of. In this case, you want v.vt = VT_ARRAY | VT_UNKNOWN. Once you change that, you'll find the memory leak is fixed.

    The customer didn't believe this explanation.

    I find this doubtful for several reasons.

    1. While this would explain why the IUnknowns in the SAFEARRAY are not released, it doesn't explain why the SAFEARRAY itself is leaked.
    2. The SAFEARRAY already contains this information, so it should already know that destroying it entails releasing the IUnknown pointers.
    3. If I manually call SafeArrayDestroy, then the IUnknowns are correctly released, confirming point 2.
    4. The function SafeArrayDestroy is never called; that is the root cause of the problem.

    The customer's mental model of PropVariantDestroy appeared to be that it should go something like this:

    if (pvt->vt & VT_ARRAY) {
     switch (pvt->vt & VT_TYPEMASK) {
     case VT_UNKNOWN:
      ... release the IUnknowns in the SAFEARRAY...
     return S_OK;

    In fact what's really going on is that the value of VT_ARRAY is interpreted as VT_ARRAY | VT_EMPTY, because (1) VT_ARRAY is a modifier, so it has to modify something, and (2) the numeric value of zero happens to be equal to VT_EMPTY. In other words, you told OLE automation that your PROPVARIANT holds a SAFEARRAY filled with VT_EMPTY.

    It also happens that a SAFEARRAY of VT_EMPTY is illegal. Only certain types can be placed in a SAFEARRAY, and VT_EMPTY is not one of them.

    The call to PropVariantClear was returning the error DISP_E_BADVARTYPE. It was performing parameter validation and rejecting the property variant as invalid, because you can't have an array of nothing. The customer's response to this explanation was very terse.

    Tx. Interesting.
  • The Old New Thing

    Why doesn't the MoveWindow function generate the WM_GETMINMAXINFO message?


    Commenter Phil Quirk asks why calling MoveWindow does not result in a WM_GETMINMAXINFO message being sent to validate the moved window size.

    Well, because you moved it after all. You're being trusted to respect your own rules. After all, if you didn't want the window to be wider than 200 pixels, you shouldn't have passed nWidth=300, right?

    The WM_GETMINMAXINFO message is for obtaining minimum and maximum sizing information when the sizes were chosen by a means outside the application's control, such as when you said "I'll let you choose the window size (CW_USEDEFAULT)" or when the user grabbed the corner of the window and started dragging it around. But if you yourself changed the window size, then the window manager assumes that you know what you're doing.

    If you don't trust yourself to follow your own rules, you can intercept the attempt to change the window size by handling the WM_WINDOWPOSCHANGING message.

Page 375 of 457 (4,568 items) «373374375376377»