October, 2011

  • The Old New Thing

    No, modifying the DLLs that come with Windows is not supported

    • 47 Comments

    From the I can't believe I had to write that file comes this question from a customer:

    Our customer is modifying the ABC.DLL file that comes with Windows in order to accomplish XYZ. Is this supported?

    No, of course this isn't supported. I can't believe I had to write that. if you modify a system file, then the thing you're running isn't Windows any more but is rather some sort of operating system that resembles Windows in many significant ways.

    (Imagine the extreme case of this: The customer modifies NTOSKRNL.EXE, KERNEL32.DLL, USER32.DLL, etc. so that they happen to be byte-for-byte identical to the files that shipped with Windows 2000. Does this mean that Microsoft supports Windows 2000?)

    The customer is just looking for an official Microsoft statement that this is not supported. They know that it's a bad idea, but their client wanted to have this feature, so when the customer tells the client "No, we can't do this," they need some sort of justification.

    Oh, I see now. The customer is chicken and wants Microsoft to be the bad cop when they deliver unfavorable news to their client.

    My fear is that the company, by being spineless, is now subject to manipulation from their client. "What, you're not going to let big old Microsoft tell you what you can and cannot do, are you? Be a man! Implement the feature!" And then the company will buckle under the pressure and implement the feature anyway.

    And then when the feature stops working at the next security hotfix (or worse, when security hotfixes stop working because you modified the file), the client will complain back to the customer, who will defensively say, "Um, yeah, stupid Microsoft broke the XYZ feature of our product. Bad! Bad Microsoft!" Or maybe the customer's plan is to change their name and move to another country so the client can't find them when everything falls apart.

  • The Old New Thing

    Why do some infotips repeat the name of the item as well as the infotip?

    • 17 Comments

    A customer noticed that when the user hovered over their application name in the Start menu, the infotip that pops up includes their product name:

    ♫ 
    Contoso Professional Music Studio Deluxe 2010
    Record and mix studio-quality music from your computer.
    Contoso Professional Music Studio De...
    ◕  Fabrikam Chart 2.0
    ℒ  Litware 2010

    ... but no other program on the Start menu included the product name in the description:

    ◕ 
    Design and print charts and graphs with ease.
    Fabrikam Chart 2.0
    ♫  Contoso Professional Music Studio De...
    ℒ  Litware 2010

    The customer compared their shortcut with the other ones but couldn't find anything that was telling Explorer, "Include the program name in the pop-up infotip, please."

    Because the reason for the name being included in the infotip had nothing to do with the properties stored in the shortcut. The reason the name was included in the infotip is that the name was being truncated in the main display.

    When an infotip is about to be displayed for a listview item, the listview sends a LVN_GET­INFO­TIP notification with a NMLV­GET­INFO­TIP structure. If the LVGIT_UNFOLDED flag is not set, then the infotip is being displayed for a truncated item, and the pszText is pre-filled with the full name. The program should then append its information to the existing text so that the full name is the first line of the infotip. On the other hand, if the LVGIT_UNFOLDED flag is set, then the item text is fully-visible and you should just copy your desired description text into the pszText buffer.

    The customer was happy to get this information. Their designer wanted only the description to appear in the infotip, and now they know that they need to shorten the program name to make the name disappear from the infotip.

    Bonus chatter: Microsoft® WinFX™ Software Development Kit for Microsoft® Pre-Release Windows Operating System Code-Named "Longhorn", Beta 1 Web Setup.

  • The Old New Thing

    Seeing the world through arbitrage-colored glasses

    • 10 Comments

    On the mailing list with a negative service level agreement, one of my colleagues posted the message

    Free Nerf guns in my office. I've decided I'm no longer a collector.

    Not one to miss the opportunity to cause some trouble, another colleague posted the message

    Nerf guns for sale: $1 each. Get'em while they're hot.

    That earned a chuckle from me.

  • The Old New Thing

    Why is there a CSIDL_DESKTOP value if you need the desktop in order to get it anyway?

    • 4 Comments

    John asks why there is a special constant CSIDL_DESKTOP defined for the desktop. After all, in order to use CSIDL_DESKTOP, you need to call SHGet­Desktop­Folder and then bind to it. What's the point of having an ITEM­ID­LIST that represents the desktop if, in order to use it, you first need to get the desktop?

    It's like asking why the file system uses . (dot) to refer to the current directory. You're already in the current directory. In order to resolve . (dot), you already need to have the current directory, so why bother with the dot at all?

    Because it is often convenient to give a name to your starting point.

    Suppose somebody wants to save a file to the desktop. How would you represent this as an ITEM­ID­LIST? If the only thing you can do is fill in the blank in the sentence, "Start with the desktop folder, then go to ________, then save the file there," then you need a way to say "where you are now."

    And that's what CSIDL_DESKTOP gives you. An ITEM­ID­LIST that says "Where you are now."

    Besides, if CSIDL_DESKTOP weren't defined, somebody would have invented it. Say your program has a list of directories it wants to operate on, say, the Documents folder, the Music folder, and the Shared Documents folder. Great, so let me write a function:

    void DoItIn(HWND hwnd, int csidl)
    {
     PIDLIST_ABSOLUTE pidl;
     if (SUCCEEDED(SHGetSpecialFolderLocation(
                         hwnd, csidl, &pidl))) {
      IShellFolder *psf;
      if (SUCCEEDED(SHBindToObject(NULL, pidl, NULL,
                        IID_PPV_ARGS(&psf)))) {
       ...
       psf->Release();
      }
      CoTaskMemFree(pidl);
     }
    }
    
    void DoItInStandardPlaces(HWND hwnd)
    {
     const static int csidls[] = {
      CSIDL_MYDOCUMENTS,
      CSIDL_MYMUSIC,
      CSIDL_COMMON_DOCUMENTS,
     };
     for (int i = 0; i < ARRAYSIZE(csidls); i++) {
      DoItIn(hwnd, csidls[i]);
     }
    }
    

    Now you want to add the desktop folder. Oh wait, there is no CSIDL value for the desktop, so I'll have to make one up.

    // Our custom CSIDLs use the high word. None of the CSIDLs we use
    // set any bits in the high word, so we can use the high word to
    // detect whether we have a standard CSIDL or a custom CSIDL.
    #define CUSTOMCSIDL_DESKTOP 0x00010000
    
    #define ISCUSTOMCSIDL(csidl) HIWORD(csidl)
    #define STANDARDCSIDLOF(csidl) LOWORD(csidl)
    
    HRESULT MyGetSpecialFolderLocation(
        HWND hwnd, int csidl, PIDLIST_ABSOLUTE *ppidl)
    {
     HRESULT hr;
     if (ISCUSTOMCSIDL(csidl)) {
      *ppidl = (PIDLIST_ABSOLUTE)CoTaskMemAlloc(sizeof(WORD));
      if (*ppidl) {
       ppidl->mkid.cb = 0;
       hr = S_OK;
      } else {
       hr = E_OUTOFMEMORY;
      }
     } else {
      hr = SHGetSpecialFolderLocation(hwnd, STANDARDCSIDLOF(csidl), ppidl);
     }
     return hr;
    }
    

    Okay, cool, now I can add

     const static int csidls[] = {
      CSIDL_MYDOCUMENTS,
      CSIDL_MYMUSIC,
      CSIDL_COMMON_DOCUMENTS,
      CUSTOMCSIDL_DESKTOP,
     };
    

    Oh wait, I also have to have a custom version of SHBind­To­Object that knows how to bind to this special new type of pidl that means "where you are now."

    HRESULT MyBindToObject(IShellFolder *psf, PCUIDLIST_RELATIVE pidl,
      IBindCtx *pbc, REFIID riid, void **ppv)
    {
     HRESULT hr;
     if (pidl->mkid.cb == 0) {
      *ppv = NULL;
      if (psf == NULL) {
       hr = SHGetDesktopFolder(&psf);
       if (SUCCEEDED(hr)) {
        hr = psf->QueryInterface(riid, ppv);
        psf->Release();
       }
      } else {
       hr = psf->QueryInterface(riid, ppv);
      }
     } else {
      hr = SHBindToObject(psf, pidl, pbc, riid, ppv);
     }
     return hr;
    }
    

    Congratulations, you just reinvented CSIDL_DESKTOP.

    It can be very convenient to have a name for the null action.

  • The Old New Thing

    When your vice president tells you to stop replying to a mail thread, you probably should stop replying to the mail thread

    • 11 Comments

    Some time in the early part of this century, somebody sent a message to the Windows NT Development Announcements mailing list at Microsoft. It went something like, "My car was parked in «location X» and somebody ran into it and didn't leave a note. Does anybody have any information about this?"

    Now, one thing you need to know is that the Windows NT Development Announcements mailing list has the entire Windows division as members. We're talking thousands of people. And the sort of announcements sent to the alias are not the "somebody dinged my car" type of announcements. They are announcements like "We will be reformatting the scratch server on Tuesday." Important stuff that everybody on the team needs to know. And it's most certainly not for discussions.

    Anyway, somebody replied to the message saying something like "Yeah, my car was parked in the same area and it got damaged, too." And then somebody else decided to be silly and wrote, "I parked my car in Germany once and it got damaged. I wonder if that's related."

    Before things could spiral out of control, Jim Allchin, vice president of Windows, stepped in and sent a message to everybody. "Stop replying to this thread."

    That shut the thread down really quickly. Nothing like your vice president telling you to shut up to get you to shut up.

    There was one reply that came through, though. It was a reply to Jim's message saying to stop replying. The person wrote, "Yes sir, captain sir. Saluting as I type, sir."

    I have no confirmation that anybody ever saw that person alive again.

    Bonus history: Today is the 14th anniversary of the infamous Bedlam Incident.

  • The Old New Thing

    The question mark lets you make up anything you like

    • 38 Comments

    A trend I've noticed in journalism is to make some sort of outrageous statement, but then stick a question mark at the end to disavow any responsibility for the statement. By changing it to a question, you're avoiding actually having to back up what you write. "I'm not saying this is actually true. I'm just raising the question."

    For example, a headline might read "The sign of something new?" The author doesn't want to actually back up the claim that the subject is the sign of something new, so he'll just say it with a question mark. Now the responsibility to support or refute the claim has been shifted to you, the reader.

    The question itself doesn't need to have any merit whatsoever. In fact, you can just make up the craziest stuff imaginable; as long as you put a question mark after it, you're home free. And it doesn't even need to take the form of a question!

    Made-up examples:

    Perhaps I should've titled this article "Journalists are just making up stuff and printing it as if it were news?"

    Bonus journalistic head-scratcher: The word "official" appears to have taken on a meaning I was previously unaware of.

    It's official: The Microsoft Zune has gone the way of the Kin, the Courier, and Bob.

    If you actually click through to the article's source, and then click through to that article's source, you'll see that the source is a person "who declined to be identified because the decision hasn't been announced."

    So let me see if I understand this. They're saying that a statement is "official" because it comes from an anonymous person who doesn't wish to be identified because no official statement has yet been made.

    (I think my copy of Gödel, Escher, Bach just exploded.)

  • The Old New Thing

    How do I set an accessible name on an unlabeled control?

    • 9 Comments

    A customer asked for advice on accessibility. This was great news, because it meant that somebody actually cared about accessibility!

    We have a property sheet page that contains an unlabeled list view. The list view is not labeled because its meaning is implied by its placement on the dialog. This works great as long as you can see the screen, but we also need to associate an accessible name to the list view so that screen readers know what it is. We tried Set­Window­Text on the list view, but accessibility didn't pick it up. How do I set the accessibility name on the control?

    Place a static control immediately ahead of the list view in the z-order. If you don't want the static control to be visible, mark it as NOT WS_VISIBLE in the dialog template.

    This is another manifestation of the trick we learned some time ago of using a hidden static control with an accelerator in order to associate the accelerator key with an unlabeled control. In this case, the hidden static control isn't there to provide an accelerator; it's there to provide an accessible name.

  • The Old New Thing

    Is there a 2048 character limit for OFN_ALLOWMULTISELECT in MFC or isn't there?

    • 17 Comments

    The MFC documentation for CFile­Dialog contains the following strange warning:

    When the user allocates their own buffer to accommodate OFN_ALLOW­MULTI­SELECT, the buffer can't be larger than 2048 or else everything gets corrupted (2048 is the maximum size).

    The sudden informality of the phrase "or else everything gets corrupted" is surprising but also sounds vaguely familiar to me. I think I was the one who wrote that phrase over a decade ago as part of my investigation into a defect in the common dialog functions. Somebody must have forwarded my analysis to the MFC documentation team (since the problem was originally in an MFC application), who just copied and pasted it into the official documentation.

    The limitation in question existed in Windows 95 and was fixed in Windows NT 4 and Windows 98, so the remarks do not apply to any modern version of Windows.

    What struck me is that the MFC documentation picked up this limitation rather than deferring to the Platform SDK team to document the issue. It means that when the bug is fixed in the platform, the MFC documentation becomes wrong.

    The limitation is not mentioned in the Visual Studio 2008 version of the CFile­Dialog documentation, which suggests either that the Visual Studio folks deferred documenting the issue to the Platform SDK team, or they somehow figured out that the issue no longer applied and removed the offending text.

  • The Old New Thing

    Microspeak: Bug jail

    • 20 Comments

    Bug jail is not a place where bugs are sent as punishment for their crimes. Rather, it's a (virtual) place that developers are sent when they have too many bugs.

    Project management establishes some maximum number of bugs (known as a bug cap) each developer is permitted to have on his or her plate, and developers whose bug count exceeds the specified maximum are placed in bug jail. The precise triggers for bug jail vary from team to team, and it may vary based on the nature of the bug. For example, one trigger might be that any Priority 0 bugs more than 24 hours old will land you in bug jail.

    Once you land in bug jail, you are not allowed to do feature work, be it coding, writing specifications, whatever. The precise triggers for getting out of bug jail also vary from team to team, but one rule might be that you need to get your bug count back down to 50% of the bug jail trigger level before you are allowed to exit.

    Staying on top of your bug count is an important part of the software development process, and the primary motivation behind bug jail is not to punish developers, although I'm sure that's how most developers perceive it. Rather, it serves as an early-warning system to highlight things that are not going smoothly. There may be a bug farm developing in that feature area. Or the team needs to revise its idea of what it means to be "done" with the feature. And it's a signal to project management that they may need to scale back their plans so as not to compromise quality and the ship schedule.

    When everybody understands the reasoning behind bug jail, you avoid lengthy discussions over boundary cases ("What if a developer is about to check in a feature but a low-priority bug comes in that pushes them over the limit?") and avoid discovering that people have been "gaming the system" (for example, by reclassifying bugs as feature requests so they don't count toward the bug cap). Like bug hugging, these sorts of games prevent project management from truly understanding how close the project is to being finished.

  • The Old New Thing

    Why does copying a file to my USB thumb drive say that the parameter is incorrect?

    • 40 Comments

    Consider the following sequence of operations, assuming that F: is a USB thumb drive with plenty of disk space.

    C:\Users\Bob\Downloads> copy readme.txt F:\
            1 file(s) copied.
    C:\Users\Bob\Downloads> copy Update.iso F:\
    The parameter is incorrect.
    

    Why is the second file copy failing?

    The hint is the file extension: *.iso, which suggests that this is a CD or DVD image, and DVD images have the feature that they tend to be really big.

    Like more than 4GB big.

    USB thumb drives tend to be formatted with the FAT32 file system rather than with NTFS. And FAT32 has a maximum file size of 4GB minus one byte.

    The user confirmed that the Update.iso file was larger than 4GB and that the USB thumb drive was formatted as FAT32.

    Mind you, the error message doesn't help at all in identifying that this is what's going on. I don't know where it's coming from, but my guess is that somewhere inside the copy command, it tries to create the destination file and set its file size. Since the file size is out of range for FAT32, the call fails with the error ERROR_INVALID_PARAMETER, and that's what ends up bubbling out to the user.

    But at least now you know what the confusing error message is trying to tell you.

Page 2 of 3 (27 items) 123