• The Old New Thing

    What was the relationship between Outlook and Outlook Express?

    • 17 Comments

    Brian wonders whether project Stimpy became Outlook Express.

    As noted in the article, projects Ren and Stimpy were merged into a single project, which became Outlook. You could say that Stimpy became Outlook, too.

    Outlook Express (code name Athena) was originally known as Internet Mail and News. This was back in the day when the cool, hip thing for Web browsers to do was to incorporate as many Internet client features as possible. In the case of Internet Mail and News, this was POP (mail) and NNTP (news).

    After Outlook became a breakout hit, the Internet Mail and News project was renamed to Outlook Express in an attempt to ride Outlook's coattails. It was a blatant grab at Outlook's brand awareness. (See also: SharePoint Workspaces was renamed OneDrive for Business; Lync was renamed Skype for Business.)

    The decision to give two unrelated projects the same marketing name created all sorts of false expectations, because it implied that Outlook Express was a "light" version of Outlook. People expected that Outlook Express could be upgraded to Outlook, or that Outlook Express and Outlook data files were compatible with each other.

    Code name reuse is common at Microsoft, and for a time, the code names Ren and Stimpy were popular, especially for projects that were closely-related. (As I vaguely recall, there was a networking client/server project that called the server Ren and the client Stimpy. But I may be misremembering, and Ren and Stimpy may just have been the names of the two source code servers.) You may have heard the names Ren and/or Stimpy in reference to some other projects. Doesn't mean that your projects are related to any others with the same name.

  • The Old New Thing

    I want you to chase your sisters until they throw up

    • 7 Comments

    A friend of mine grew up in a rural area. The family got their water from a well and had to fluoridate it manually with tablets.

    When my friend was a little girl, she was playing around the house with one of her friends (let's call her friend Alice). They got into the kitchen cabinet and found these candy-like things and ate them. When her mother discovered that they had eaten fluoride tablets, she called the poison control center for advice. In addition to telling her to give the girls something-or-other, they instructed her to keep the girls moving until they vomited up the tablets.

    As it happens, my friend's brother and Alice's brother were playing outside. The boys were called inside, informed of what happened, and instructed to keep their sisters moving and try to get them to throw up.

    The boys couldn't believe their ears. You want us to chase our sisters until they throw up? This must be what heaven is like!

    The boys assumed their responsibilities with great enthusiasm, chasing the girls around the yard, putting them in a swing and spinning them around, all the stuff brothers dream of doing to torment their sisters, but this time they could do it without fear of punishment. Fortunately, the story had a happy ending. The girls soon vomited up the tablets and thereby avoided two horrible fates: (1) fluoride poisoning and (2) being forced to endure torture from their brothers in perpetuity.

  • The Old New Thing

    How do I make a boldface item on a context menu?

    • 3 Comments

    Today's Little Program displays a context menu with a bold item. I sort of talked about this some time ago, but now I'm going to actually do it. Remember, the boldface item represents the default item. You should set it to the action that would have taken place if the user had double-clicked the object.

    Start with our scratch program and make the following changes:

    void OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
    {
     HMENU hmenu = CreatePopupMenu();
     AppendMenu(hmenu, MF_STRING, 100, TEXT("&First"));
     AppendMenu(hmenu, MF_STRING, 101, TEXT("&Second"));
     AppendMenu(hmenu, MF_STRING, 102, TEXT("&Third"));
    
     SetMenuDefaultItem(hmenu, 101, FALSE);
    
     TrackPopupMenuEx(hmenu, 0, xPos, yPos, hwnd, nullptr);
    
     DestroyMenu(hmenu);
    }
    
        HANDLE_MSG(hwnd, WM_CONTEXTMENU, OnContextMenu);
    

    Note that for expository purposes (this is a Little Program, after all), I am not heeding the advice I gave some time ago. As a result, this program does not support multiple monitors or keyboard-invoked context menus. Read the linked article for instructions on how to fix the code.

    When you right-click on the window, the On­Context­Menu function creates a pop-up window, fills it with some dummy commands, and says that item 101 should be the default. Then it displays the context menu to the user, throws away the result, and destroys the menu to avoid a memory leak.

    When the menu pops up, the item Second appears in boldface.

  • The Old New Thing

    Flaw reported in Windows 95

    • 23 Comments

    One of my colleagues ran across this old news clipping from 20 years ago today.

    Flaw reported in Windows 95

    THE ASSOCIATED PRESS

    SAN MATEO, Calif. — Microsoft Corp.'s long-awaited Windows 95 operating system has a flaw that can freeze up computers when running certain applications, InfoWorld magazine said Friday.

    The company is aware of the problem but is shipping 450,000 anyway as part of a preview program, the magazine said.

    "I fear that unless Microsoft goes back to the drawing board on this operating system, only light users will get anything out of it," said Nicholas Petreley, the magazine's executive editor.

    He said the system's inability to handle several types of sophisticated applications at the same time made it questionable for business use.

    I can't find a copy of the original InfoWorld article online; all I can find are citations to it, like this one and this one.

    The clipping had a handwritten note attached:

    Bob,
    You guys may want to respond to this.
    Mom

    The report was shortly followed by a rebuttal from Windows Magazine, pointing out that this was a beta release, it is not unusual that an unfinished product has bugs, and that a similar bug in an earlier beta was fixed within two weeks.

    ZOMG! A beta product has a bug!

    I found it cute that my colleague's mother chose to bring this article to her son's attention.

  • The Old New Thing

    Switching on a tuple: Sneaky trick

    • 31 Comments

    This is a sneaky trick, but it's sometimes a handy sneaky trick.

    Suppose you have two values, and you want to switch on the tuple. In other words, you want a switch statement for something like this:

    if (val1 == 1 && val2 == 0) {
     Thing_1_0();
    } else if ((val1 == 1 && val2 == 1 ||
               (val1 == 1 && val2 == 2)) {
     Thing_1_12();
    } else if (val1 == 2 && val2 == 0) {
     Thing_2_0();
    } ... etc ...
    

    You could try writing

    switch (val1, val2) {
    case 1, 0:
        Thing_1_0();
        break;
    case 1, 1:
    case 1, 2:
        Thing_1_12();
        break;
    case 2, 0:
        Thing_2_0();
        break;
    ...
    }
    

    but that doesn't do what you think it does. (Because that comma is a comma operator.)

    The sneaky trick is to pack the two values into a single value that you can then switch on.

    switch (MAKELONG(val1, val2)) {
    case MAKELONG(1, 0):
        Thing_1_0();
        break;
    case MAKELONG(1, 1):
    case MAKELONG(1, 2):
        Thing_1_12();
        break;
    case MAKELONG(2, 0):
        Thing_2_0();
        break;
    ...
    }
    

    Note that there are dangers here beyond craziness. You have to make sure that your packing function is injective (i.e., that it does not assign the same packed value to two different inputs). If you use MAKE­LONG as your packing function, then the two values to be packed must fit into 16-bit integers.

  • The Old New Thing

    What's the difference between PathIsSystemFolder and Protected Operating System Files?

    • 17 Comments

    The way to detect weird directories that should be excluded from the user interface is to check for the FILE_ATTRIBUTE_HIDDEN and FILE_ATTRIBUTE_SYSTEM attributes being set simultaneously. This is the mechanism used when you uncheck Hide protected operating system files in the Folder Options dialog. (Programmatically, you detect whether the user wants to see protected operating system files by checking the fShow­Super­Hidden member of the SHELL­STATE structure.)

    Michael Dunn suggested using Path­Is­System­Folder to detect these special directories, but that is not quite right.

    Path­Is­System­Folder is for marking a directory as "This directory has a nondefault UI behavior attached to it. Please consult the desktop.ini file for more information." You do this when your directory is, say, the root of a namespace extension, or it has been subjected to folder customization. Windows uses it to indicate that the directory has a localized name, as well as other funky internal state.

    There are two ways to mark a folder as having nondefault UI. One is to set the FILE_ATTRIBUTE_READ­ONLY attribute, and the other is to set the FILE_ATTRIBUTE_SYSTEM attribute.

    Either one works, and Path­Is­System­Folder checks for both, returning a nonzero value if either attribute is set.

    In its default configuration, Windows uses the read-only flag to mark folders with nondefault UI. However, some applications mistakenly believe that if a directory is marked read-only, then files within the directory cannot be modified. As a result, these applications refuse to let you save your documents onto the desktop, for example. To work around this, you can use the Use­System­For­System­Folders to tell Windows to use the FILE_ATTRIBUTE_SYSTEM attribute instead. Of course, if you do that, you will run into problems with applications which mistakenly believe that if a directory is marked system, then the directory is inaccessible. So you get to pick your poison.

    Programmers who wish to mark a folder as having nondefault UI should use the Path­Make­System­Folder function to set the appropriate attribute. That function consults the system policy and sets the attribute that the policy indicates should be used to mark folders with nondefault UI.

    Going back to the original question, then: The difference between Path­Is­System­Folder and checking for folders that are marked hidden+system is that they check different things and have different purposes.

    Function Test
    Path­Is­System­Folder ReadOnly or System
    path is protected operating system folder Hidden and System
  • The Old New Thing

    A Venn diagram demonstrating the dining options in one of the new cafeterias

    • 27 Comments

    Back in the early 2000s, a new building opened on the Microsoft main campus, and the food services department tried an experiment: Instead of creating a standard cafeteria, they decided to make the cafeteria in the new building a specialty cafeteria. This new cafeteria was more like a deli, specializing in offerings like antipasto, rotisserie chicken, and grilled panini sandwiches.

    The idea was that the building would generate cross-building foot traffic with the building next door. The food services department figured that people would typically go to the cafeteria in the old building next door, but if they had a hankering for something offered by the specialty cafeteria, they could walk over to the new cafeteria.

    It was an interesting idea, but it didn't work out well in practice because people are lazy and always go to the nearest cafeteria. This meant that the people who worked in the new building wandered into their cafeteria and saw the same specialty offerings every day. And nobody from the other cafeteria ever came to visit the specialty cafeteria.

    One of my colleagues explained the dining options in the new cafeteria with a Venn diagram:

    Rotisserie
    chicken
    Panini
    sandwiches
    Chicken
    panini
    sandwiches

    After a few months, the food services department realized that their plan wasn't working out too well, and they converted the new cafeteria into a more traditional cafeteria.

  • The Old New Thing

    CancelIoEx can cancel I/O on console input, which is kind of nice

    • 24 Comments

    Today's Little Program asks you to type something, but gives you only two seconds to do it. This is not interesting in and of itself, but it shows you how to cancel console I/O. There is no motivation for this exercise because Little Programs come with little to no motivation.

    Okay, fine, here's the motivation.

    We have a GUI application that has a debug console. When the user exits the application, we cannot shut down cleanly because the debug console is stuck on a read from stdin. We want to unstick the thread gently. We don't want to use Generate­Console­Ctrl­Event with CTRL_C_EVENT because that will send the event to all processes using the same console, but we don't want other processes to be affected.

    Okay, now our Little Program.

    #include <windows.h>
    #include <stdio.h> // horrors! mixing C and C++!
    
    DWORD CALLBACK ThreadProc(void *)
    {
     Sleep(2000);
     CancelIoEx(GetStdHandle(STD_INPUT_HANDLE), nullptr);
     return 0;
    }
    
    int __cdecl wmain(int, wchar_t **)
    {
     DWORD scratch;
     HANDLE h = CreateThread(nullptr, 0, ThreadProc,
                             nullptr, 0, &scratch);
     if (h) {
      printf("type something\n");
      char buffer[80];
      if (fgets(buffer, 80, stdin) != nullptr) {
       printf("you typed %s", buffer);
      } else if (feof(stdin)) {
       printf("end-of-file reached\n");
      } else if (ferror(stdin)) {
       printf("error occurred\n");
      }
     }
     return 0;
    }
    

    If you type something within two seconds, it is reported back to you, but if you take too long, then the Cancel­Io­Ex cancels the console read, and you get an error back.

    If you want to continue, you'll have to clearerr(stdin), but if you just want to unstick the code that is performing the read (so that you can get the program to exit cleanly), then leaving stdin in an error state is probably better.

    (If you had used Read­File instead of fgets, the read would have failed with error code ERROR_OPERATION_ABORTED, as documented by Cancel­Io­Ex.)

  • The Old New Thing

    Finding the constructor by scanning memory for the vtable

    • 5 Comments

    In Looking for leaked objects by their vtable, we used the object's constructor to locate the vtable, and then scanned the heap for the vtable to find the leaked object. But you can run this technique in reverse, too.

    Suppose you found an object and you want to find its constructor. This is not a problem if you have the source code, but if you are doing some reverse-engineering for application compatibility purposes, you don't have the luxury of the application source code. You may have figured out that the application fails because the byte at offset 0x50 is zero, but on the previous version of Windows, it was nonzero. You want to find out who sets the byte at offset 0x50, so that you can see why it is setting it to zero instead of a nonzero value.

    If the object has a vtable, you can scan the code segments for a copy of the vtable. It will show up in an instruction like

    mov dword ptr [reg], vtable_address
    

    This is almost certainly the object's constructor, setting up the object vtable as part of construction. You can set a breakpoint here to break when the object is constructed, and then you can set a write breakpoint on offset 0x50 to see where its value is seto.

  • The Old New Thing

    Sure, we have RegisterWindowMessage and RegisterClipboardFormat, but where are DeregisterWindowMessage and DeregisterClipboardFormat?

    • 23 Comments

    The Register­Window­Message function lets you create your own custom messages that are globally unique. But how do you free the message format when you're done, so that the number can be reused for another message? (Similarly, Register­Clipboard­Format and clipboard formats.)

    You don't. There is no Deregister­Window­Message function or Deregister­Clipboard­Format function. Once allocated, a registered window message and registered clipboard format hangs around until you log off.

    There is room for around 16,000 registered window messages and registered clipboard formats, and in practice exhaustion of these pools of numbers is not an issue. Even if every program registers 100 custom messages, you can run 160 unique programs before running into a problem. And most people don't even have 160 different programs installed in the first place. (And if you do, you almost certainly don't run all of them!) In practice, the number of registered window messages is well under 1000.

    A customer had a problem with exhaustion of registered window messages. "We are using a component that uses the Register­Window­Message function to register a large number of unique messages which are constantly changing. Since there is no way to unregister them, the registered window message table eventually fills up and things start failing. Should we use Global­Add­Atom and Global­Delete­Atom instead of Register­Window­Message? Or can we use Global­Delete­Atom to delete the message registered by Register­Window­Message?"

    No, you should not use Global­Add­Atom to create window messages. The atom that comes back from Global­Add­Atom comes from the global atom table, which is different from the registered window message table. The only way to get registered window messages is to call Register­Window­Message. Say you call Global­Add­Atom("X") and you get atom 49443 from the global atom table. Somebody else calls Register­Window­Message("Y") and they get registered window message number 49443. You then post message 49443 to a window, and it thinks that it is message Y, and bad things happen.

    And you definitely should not use Global­Delete­Atom in a misguided attempt to deregister a window message. You're going to end up deleting some unrelated atom, and things will start going downhill.

    What you need to do is fix the component so it does not register a lot of window messages with constantly-changing names. Instead, encode the uniqueness in some other way. For example, instead of registering a hundred messages of the form Contoso user N logged on, just register a single Contoso user logged on message and encode the user number in the wParam and lParam payloads. Most likely, one or the other parameter is already being used to carry nontrivial payload information, so you can just add the user number to that payload. (And this also means that your program won't have to keep a huge table of users and corresponding window messages.)

    Bonus chatter: It is the case that properties added to a window via Set­Prop use global atoms, as indicated by the documentation. This is an implementation detail that got exposed, so now it's contractual. And it was a bad idea, as I discussed earlier.

    Sometimes, people try to get clever and manually manage the atoms used for storing properties. They manually add the atom, then access the property by atom, then remove the properties, then delete the atom. This is a high-risk maneuver because there are so many things that can go wrong. For example, you might delete the atom prematurely (unaware that it was still being used by some other window), then the atom gets reused, and now you have a property conflict. Or you may have a bug that calls Global­Delete­Atom for an atom that was not obtained via Global­Add­Atom. (Maybe you got it via Global­Find­Atom or Enum­Props.)

    I've even seen code that does this:

    atom = GlobalAddAtom(name);
    
    // Some apps are delete-happy and run around deleting atoms they shouldn't.
    // If they happen to delete ours by accident, things go bad really fast.
    // Prevent this from happening by bumping the atom refcount a few extra
    // times so accidental deletes won't destroy it.
    GlobalAddAtom(name);
    GlobalAddAtom(name);
    

    So we've come full circle. There is a way to delete an unused atom, but people end up deleting them incorrectly, so this code tries to make the atom undeletable. Le Chatelier's Principle strikes again.

Page 1 of 446 (4,454 items) 12345»