• The Old New Thing

    Flaw reported in Windows 95

    • 16 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

    • 29 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

    • 25 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.

  • The Old New Thing

    Travel tip: Don't forget your car on the ferry

    • 26 Comments

    One of my colleagues lives on Bainbridge Island and has quite a long commute to work each day. From his house, he walks to the bus stop, then takes the bus to the Winslow ferry terminal, then takes the ferry to the Seattle ferry terminal, then takes the bus to Microsoft. And at the end of the day, he does the trip in reverse.

    One day, for whatever reason, he drove to work instead of taking the bus. He drove to the ferry terminal, took the ferry across, then drove to work. And at the end of the day, he drove to the ferry, but when the ferry arrived at its destination, he forgot that he had driven his car and walked off the boat to the bus.

    While on his way home on the bus, he got a phone call from his wife. "Did you forget your car on the ferry, dear?"

    Oops.

    Now, leaving your car on the ferry is a bad thing not just because your car is now an obstacle on the ferry deck which all the other drivers must maneuver around. When there is an abandoned car on the deck, one of the possibilities that must be investigated is that a passenger has fallen overboard.

    The crew took the ship offline, conducted a search of the vessel, and initiated a search-and-rescue operation along the ferry route, looking for a body floating in the water.

    My colleague had to sheepishly call the ferry authorities and say, "Hello, I believe you're looking for me."

    (Today is Transit Driver Appreciation Day, but I don't think your ferry captain will complain if you thank him/her, too.)

  • The Old New Thing

    Microspeak: Headcount, req, and related personnel terms

    • 16 Comments

    For some reason, there are a lot of Microspeak terms related to personnel. (Maybe you folks can tell me how common these terms are outside Microsoft.)

    We start with a term that is not actually used much outside the personnel world: The Position Control Number, or PCN. The PCN represents a place where an employee could be hired. If somebody is actually hired for the position, then the PCN is filled; if not, then it is unfilled.

    The term you are likely to hear outside of the personnel world is headcount. (Pronounced as the two words head count, accent on the first word.) This is a filled PCN, and it is often abbreviated to just head.

    Another term you are likely to hear is a req, short for requisition, and pronounced like the word wreck. A req is a requisition to recruit; in other words, it is permission to look for somebody to fill a position.

    We have an open req to find somebody to frob the whatsit so it can futz the doodad.

    An open req is a req that has not yet been filled. This sounds redundant to me, because a req by definition is unfilled, isn't it?

    Yet another personnel term you may encounter is backfill. This refers to hiring someone to take over a position that has been vacated by somebody who left the team. You will sometimes hear the term used in a metaphorical context.

    Who is the backfill for Bob while he is on vacation?

    Bob has not actually left the team; the person merely wants to know who is covering Bob's responsibilities while he is on vacation.

    The last term I'm going to expose you to is the ROP, or Recruiting Only Position. A ROP is permission to interview someone for a position that doesn't exist yet. You open a ROP with a particular person in mind, and once obtained, you have permission to interview them. You can think of a ROP as unapproved headcount, since if you decide to hire the person, you still have to find a PCN to put them in. And if you decide not to hire the person after you interviewed them, you close the ROP.

    I have no idea how useful these terms are for people not in the personnel world, but I figured I'd write them down for my own benefit, so I have something to refer to when I run across them.

  • The Old New Thing

    Does the CLR really call CoInitializeEx on the first call to unmanaged code, even if you don't deal with COM at all and are just calling native code via p/invoke?

    • 13 Comments

    Some time ago, I called out this part of the documentation regarding managed and unmanaged threading:

    On the first call to unmanaged code, the runtime calls Co­Initialize­Ex to initialize the COM apartment as either an MTA or an STA apartment. You can control the type of apartment created by setting the System.Threading.ApartmentState property on the thread to MTA, STA, or Unknown.

    Commenter T asks, "Does it do this even if you don't deal with COM at all and call native code through a P/Invoke?"

    Well, the documentation says it does, and we can confirm with an experiment:

    using System.Runtime.InteropServices;
    
    class Program
    {
     public static void Main()
     {
      var thread = new System.Threading.Thread(
        () => {
       System.Console.WriteLine("about to p/invoke");
       GetTickCount();
      });
      thread.Start();
      thread.Join();
     }
    
     [DllImport("kernel32.dll")]
     extern static uint GetTickCount();
    }
    

    Run this program with a breakpoint on Co­InitializeEx.

    First breakpoint is hit with this stack:

    rax=00007ffebc529b70 rbx=00000000007c6100 rcx=0000000000000000
    rdx=0000000000000000 rsi=0000000000000001 rdi=0000000000000002
    rip=00007ffebc529b70 rsp=000000000056f038 rbp=000000000056f0b0
     r8=0000000000000001  r9=0000000000000000 r10=0000000000000000
    r11=0000000000000037 r12=0000000000004000 r13=0000000000000001
    r14=0000000000000001 r15=0000000000000001
    
    combase!CoInitializeEx
    clr!Thread::SetApartment
    clr!SystemDomain::SetThreadAptState
    clr!SystemDomain::ExecuteMainMethod
    clr!ExecuteEXE
    clr!_CorExeMainInternal
    clr!CorExeMain
    mscoreei!CorExeMain
    MSCOREE!CorExeMain_Exported
    KERNEL32!BaseThreadInitThunk
    ntdll!RtlUserThreadStart
    

    This call is initializing the main thread of the process. The flags passed to this first call to Co­Initialize­Ex are 0, which means that the default threading model of COINIT_MULTI­THREADED is used.

    The next time the breakpoint hits is with this stack:

    rax=00000000ffffffff rbx=00000000007d1180 rcx=0000000000000000
    rdx=0000000000000000 rsi=0000000000000001 rdi=00000000007d1180
    rip=00007ffebc529b70 rsp=000000001a6af9a8 rbp=000000001a6afa20
     r8=000000001a6af948  r9=0000000000000000 r10=00000000007f0340
    r11=00000000007f0328 r12=0000000000004000 r13=0000000000000000
    r14=0000000000000000 r15=0000000000000000
    
    combase!CoInitializeEx
    clr!Thread::SetApartment
    clr!Thread::DoExtraWorkForFinalizer
    clr!WKS::GCHeap::FinalizerThreadWorker
    clr!ManagedThreadBase_DispatchInner
    clr!ManagedThreadBase_DispatchMiddle
    clr!ManagedThreadBase_DispatchOuter
    clr!WKS::GCHeap::FinalizerThreadStart
    clr!Thread::intermediateThreadProc
    KERNEL32!BaseThreadInitThunk
    ntdll!RtlUserThreadStart
    

    From the name Finalizer­Thread­Start, this is clearly the finalizer thread.¹

    Next.

    rax=00000000ffffffff rbx=000000000039eb20 rcx=0000000000000000
    rdx=0000000000000000 rsi=0000000000000001 rdi=0000000000000000
    rip=00007ffebc529b70 rsp=000000001a5af3d8 rbp=000000001a5af450
     r8=0000000000000000  r9=000000001a5af3f0 r10=0000000000000000
    r11=0000000000000286 r12=0000000000004000 r13=0000000000000000
    r14=0000000000000000 r15=0000000000000000
    
    combase!CoInitializeEx
    clr!Thread::SetApartment
    clr!Thread::PrepareApartmentAndContext
    clr!Thread::HasStarted
    clr!ThreadNative::KickOffThread
    clr!Thread::intermediateThreadProc
    KERNEL32!BaseThreadInitThunk
    ntdll!RtlUserThreadStart
    

    Okay, this looks like it's kicking off a new thread. I inferred this from the presence on the stack of the function which is deviously named Kick­Off­Thread.

    And the flags passed to this call to Co­Initialize­Ex are 0, which once again means that it defaults to MTA.

    There, we have confirmed experimentally that, at least in this case, the implementation matches the documentation.

    That the implementation behaves this way is not surprising. After all, the CLR does not have insight into the Get­Tick­Count function. It does not know a priori whether that function will create any COM objects. After all, we could have been p/invoking to SHGet­Desktop­Folder, which does use COM. Given that the CLR cannot tell whether a native function is going to use COM or not, it has to initialize COM just in case.

    ¹ Or somebody who is trying to mislead us into thinking that it is the finalizer thread. I tend to discount this theory because as a general rule, code is not intentionally written to be impossible to understand.

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