November, 2009

  • The Old New Thing

    Hey, is there somebody around to accept this award?

    • 66 Comments

    Back in the late 1990s, some large Internet association conducted a survey in order to bestow awards in categories like Best Web server and Best Web browser, and one of the categories was Best Web authoring tool.

    We didn't find out about this until the organization contacted the Windows team and said, "Hi, we would like to present Microsoft with the award for Best Web authoring tool. Please let us know who the author of Notepad is, so that we can invite them to the award ceremony."

    Yup, Notepad won the award for Best Web authoring tool.

    The mail went out to the team. "Hey, does anybody remember who wrote Notepad?"

    Even a decade ago, the original authorship of Notepad was lost to the mists of time. I think the person who ended up going was the original author of the multi-line edit control, since that's where the guts of Notepad lie.

  • The Old New Thing

    Stories of anticipating dead computers: Windows Home Server

    • 65 Comments

    Like most geeks, I have a bit of history with dead computers. In the past, I used the "wait until it breaks, and then panic" model, but recently I've begun being a bit more anticipatory, like replacing an old laptop before it actually expires.

    Anticipating another future dead computer, I bought an external USB hard drive for backing up important files, but upon reading the description on the box, I started to have second thoughts. It came with its own backup software that reportedly installed automatically when you plugged in the drive (!). I didn't want that; I just wanted a boring USB hard drive.

    One of my friends (who used to work with USB devices) cautioned me: "Those things are evil. Some of them enumerate as a keyboard and 'type in' a device driver so they can own your machine even if you have autorun disabled." Wow, that's a level of craziness I previously had not been aware of.

    Upon further discussion, I was convinced to return the external hard drive unopened and instead get a copy of Windows Home Server. I went for the Acer Aspire EasyStore H340 instead of trying to build my own reduced-footprint low-power quiet-fan computer. And amazingly, the EasyStore comes with only two pieces of shovelware, the excellent LightsOut add-in, which I kept, and some annoying trialware, which was easily uninstalled.

    I felt kind of weird getting a Home Server since I have only one home computer of consequence, so I'd basically have a one-computer network. (I do have that laptop, but I'm careful not to keep anything on it that isn't already backed up somewhere else.) And because the Home Server would easily be the most powerful computer in the house, even though all it does is sit there doing nothing most of the time. But the convenience is hard to beat. It just sits there quietly and does its job of backing up the other computer every night. (And seeing as I had the machine anyway, I also have it back up my laptop, even though there's nothing really important on it. Most nights, the laptop backup takes only five minutes. And just because I can, I even back up the old laptop that doesn't even do anything any more aside from surf the Internet!)

    Of course, the first thing you do with a new gadget is tinker with it, and I installed Whiist and created a photo album. It was so easy to do, I feel like I'm losing my geek cred. I mean, this sort of thing is supposed to involve hours of staring at the screen, scouring the Internet for information, and groveling through hundreds of settings trying to get things working. If anybody can get a home server up and running with automatic nightly backups and an online photo album by just clicking on some fluffy GUI buttons, then what will I have to feel superior about?

    I'm kidding. My hat's off to the legendary Charlie Kindel and the Windows Home Server team They hit this one out of the park. It's an awesome product.

    Now that backing up is so painless, it has set a new baseline behavior: Now, I feel kind of uneasy making large-scale changes to files on my home computer unless I have a complete backup. (Backups are the reason I bought the server. All the other features, like the photo album, are just gravy.)

    And yes, every few weeks, I restore a randomly-selected file from backup just to make sure the backups are working.

    FTC disclaimer: Although Windows Home Server is a product of Microsoft Corporation (my employer), no compensation was tied to this review. (I didn't even get an employee discount.) I'm just a happy customer.

  • The Old New Thing

    Little-known command line utility: clip

    • 55 Comments

    Windows Vista includes a tiny command line utility called clip. All it does is paste its stdin onto the clipboard.

    dir | clip
    echo hey | clip
    

    For the opposite direction, I use a little perl script:

    use Win32::Clipboard;
    print Win32::Clipboard::GetText();
    
  • The Old New Thing

    When computer programmers dabble in making change

    • 51 Comments

    My colleague who dabbled in economics when deciding how many lunch vouchers to buy had a number of other money-related quirks.

    One of the ones that I remember is that when paying for a purchase, my colleague would double the balance and give the cashier that much money. For example, if the total was $5.20, my colleague would hand over $10.40.

    Why?

    Just to see if the cashier reacted when pressing the Enter code appeared to have no effect.

    Total is $5.20.

    Cash tendered is $10.40.

    Change is $5.20.

    Most of the time, the cashier wouldn't pay any attention. Heck, the cashier wouldn't even question why my colleague handed over such a strange amount of money.

    Sometimes my colleague would mix it up and instead add $6.66 to the total. For example, if the total was $5.20, my colleague would hand over $11.86, just to see the cashier's reaction when the cash register indicated that the change due was $6.66.

    And then one day, magic happened: The total was $6.66. Without skipping a beat, my colleague handed over $13.32.

  • The Old New Thing

    We found the author of Notepad, sorry you didn't go to the award ceremony

    • 34 Comments

    I've received independent confirmations as to the authorship of Notepad, so I'm inclined to believe it. Sorry you didn't get to go to the award ceremony.

    The original author of Notepad also served as the development manager for Windows 95. His job was to herd the cats that made up the programmers who worked on Windows 95, a job which you can imagine falls into the "not easy" category.

    After Windows 95, he retired from the software industry and became a high school science teacher. At a social event some years later, I met him again and asked about the transition from software development manager to high school science teacher.

    His response: "You'd be surprised how many of the skills transfer."

  • The Old New Thing

    Trying to avoid double-destruction and inadvertently triggering it

    • 34 Comments

    We saw some time ago the importance of artificially bumping an object's reference count during destruction to avoid double-destruction. However, one person's attempt to avoid this problem ended up triggering it.

    ULONG MyObject::Release()
    {
     LONG cRef = InterlockedDecrement(&m_cRef);
     if (cRef > 0) return cRef;
     m_cRef = MAXLONG; // avoid double-destruction
     delete this;
     return 0;
    }
    

    The explanation for the line m_cRef = MAXLONG was that it was done to avoid the double-destruction problem if the object receives a temporary AddRef/Release during destruction.

    While it's true that you should set the reference count to an artificial non-zero value, choosing MAXLONG has its own problem: integer overflow.

    Suppose that during the object's destruction, the reference count is temporarily incremented twice and decremented twice.

    Action m_cRef
    Just before call to Release() 1
    InterlockedDecrement 0
    m_cRef = MAXLONG 2147483647
    destructor does temporary AddRef() −2147483648 (integer overflow)
    destructor does temporary AddRef() −2147483647
    destructor does temporary Release() −2147483648
    since m_cRef < 0, we re-destruct

    Sure, choosing a huge DESTRUCTOR_REFCOUNT means that you have absolutely no chance of decrementing the reference count back to zero prematurely. However, if you choose a value too high, you introduce the risk of incrementing the reference count so high that it overflows.

    That's why the most typical values for DESTRUCTOR_REFCOUNT are 1, 42, and 1000. The value 1 is really all you need to avoid double-destruction. Some people choose 42 because it's cute, and other people choose 1000 because it's higher than any "normal" refcount, so it makes it easier to spot during debugging. But even then, the "high" value of 1000 still leaves room for over two billion AddRef()s before overflowing the reference count.

    On the other hand, if you choose a value like MAXLONG or MAXDWORD, then you're taking something that previously never happened (reference count integer overflow) and turning it into an almost certainty.

  • The Old New Thing

    I reorganized your kitchen for you, sweetie

    • 29 Comments

    I suspect most people are familiar with the It may be a mess, but it's my mess and I know where everything is phenomenon. That doesn't necessarily mean that items are in the best location, but at least you know which suboptimal location you chose.

    :: Wendy :: told me a story some time ago about something that happened while her parents were visiting. When she returned from work, her mother said, "Oh, Wendy, darling, I reorganized your kitchen for you. You had everything in the wrong place."

    Wendy's mother was trying to be helpful, but of course it was a net loss for poor Wendy, who couldn't find anything in her kitchen for weeks. Yes, there was the whole Oh great where did my mother put my food processor? problem, but even after she found it, the "improved" location was far worse than its original location. In fact, in many cases, it was in the exact opposite location from where it should be.

    You see, Wendy is left-handed, and her mother is right-handed.

  • The Old New Thing

    We're using a smart pointer, so we can't possibly be the source of the leak

    • 29 Comments

    A customer reported that there was a leak in the shell, and they included the output from Application Verifier as proof. And yup, the memory that was leaked was in fact allocated by the shell:

    VERIFIER STOP 00000900 : pid 0x3A4: A heap allocation was leaked.
    
            497D0FC0 : Address of the leaked allocation.
            002DB580 : Adress to the allocation stack trace.
            0D65CFE8 : Address of the owner dll name.
            6F560000 : Base of the owner dll.
    
    1: kd> du 0D65CFE8
    0d65cfe8  "SHLWAPI.dll"
    
    1: kd> !heap -p -a 497D0FC0
    ...
        ntdll!RtlpAllocateHeap+0x0003f236
        ntdll!RtlAllocateHeap+0x0000014f
        Kernel32!LocalAlloc+0x0000007c
        shlwapi!CreateMemStreamEx+0x00000043
        shlwapi!CreateMemStream+0x00000012
        <Unloaded_xyz.dll>+0x000642de
        <Unloaded_xyz.dll>+0x0005e2af
        <Unloaded_xyz.dll>+0x0002d49a
        <Unloaded_xyz.dll>+0x0002a0fd
        <Unloaded_xyz.dll>+0x000289cb
        <Unloaded_xyz.dll>+0x0002a25c
        <Unloaded_xyz.dll>+0x00027225
        <Unloaded_xyz.dll>+0x0002252b
        <Unloaded_xyz.dll>+0x00025394
        <Unloaded_xyz.dll>+0x0004d70f
        Kernel32!BaseThreadInitThunk+0x0000000d
        ntdll!RtlUserThreadStart+0x0000001d
    
    1: kd> dps 002DB580
    shlwapi!CreateMemStreamEx+0x43
    shlwapi!CreateMemStream+0x12
    <Unloaded_xyz.dll>+0x642de
    <Unloaded_xyz.dll>+0x5e2af
    <Unloaded_xyz.dll>+0x2d49a
    <Unloaded_xyz.dll>+0x2a0fd
    <Unloaded_xyz.dll>+0x289cb
    <Unloaded_xyz.dll>+0x2a25c
    <Unloaded_xyz.dll>+0x27225
    <Unloaded_xyz.dll>+0x2252b
    <Unloaded_xyz.dll>+0x25394
    <Unloaded_xyz.dll>+0x4d70f
    Kernel32!BaseThreadInitThunk+0xd
    ntdll!RtlUserThreadStart+0x1d
    

    On the other hand, SHCreateMemStream is an object creation function, so it's natural that the function allocate some memory. The responsibility for freeing the memory belongs to the caller.

    We suggested that the customer appears to have leaked the interface pointer. Perhaps there's a hole where they called AddRef and managed to avoid the matching Release.

    "Oh no," the customer replied, "that's not possible. We call this function in only one place, and we use a smart pointer, so a leak is impossible." The customer was kind enough to include a code snippet and even highlighted the lines that proved they weren't leaking.

    CComPtr<IStream> pMemoryStream;
    CComPtr<IXmlReader> pReader;
    UINT nDepth = 0;
    
    //Open read-only input stream
    pMemoryStream = ::SHCreateMemStream(utf8Xml, cbUtf8Xml);
    

    The exercise for today is to identify the irony in the highlighted lines.

    Hint. Answers (and more discussion) tomorrow.

  • The Old New Thing

    How do I get the command line of another process?

    • 28 Comments

    Win32 doesn't expose a process's command line to other processes. From Win32's point of view, the command line is just a conveniently initialized parameter to the process's startup code, some data copied from the launching process to the new process and forgotten. We'll get back to the Win32 point of view a little later.

    If you look around in WMI, you'll find a Win32_Process object, and lo and behold, it has a CommandLine property. Let's check it out, using the standard WMI application:

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colItems = objWMIService.ExecQuery("Select * from Win32_Process")
    For Each objItem in colItems
         Wscript.Echo objItem.Name
         Wscript.Echo objItem.CommandLine
    Next
    

    I fully anticipate that half of my readers will stop right there. "Thanks for the script. Bye!" And they won't bother reading the analysis. "Because analysis is boring, and it'll just tell me stuff I don't want to hear. The analysis is going to tell me why this won't work, or why it's a bad idea, and that just cramps my style."

    Remember that from Win32's point of view, the command line is just a string that is copied into the address space of the new process. How the launching process and the new process interpret this string is governed not by rules but by convention.

    What's more, since the string is merely a "preinitialized variable", a process could in principle (and many do in practice, although usually inadvertently) write to the memory that holds the command line, in which case, if you go snooping around for it, you'll see the modified command line. There is no secret hiding place where the kernel keeps the "real original command line," any more than there is a secret hiding place where the C compiler keeps the "real original parameters to a function."

    This is just another manifestation of the principle of not keeping track of information you don't need.

    What does this mean for people who disregard this principle and go after the command line of another process? You have to understand what you are getting is non-authoritative information. In fact, it's worse. It's information the application itself may have changed in order to try to fool you, so don't use it to make important decisions.

  • The Old New Thing

    Why does shlwapi import a nonexistent function?

    • 27 Comments
    Commenter charless asks why shlwapi.dll imports a nonexistent function from mpr.dll, which shows up in dependency tools as a broken import.

    Because that function did exist at one point, although it doesn't exist any more.

    The function in question was available only on Windows 95-series versions of Windows. It never existed on Windows NT or any of its successors. But remember that shlwapi.dll was originally developed for Internet Explorer, which ran on Windows 95 as well as Windows NT. Internet Explorer checked the operating system and called the Windows 95-only function only after verifying that it was running on Windows 95. If it was running on Windows NT, then it never called the function and therefore never stepped on the land mine known as ERROR_PROC_NOT_FOUND.

    Okay, so why does shlwapi still link to the function long after the Windows 95 series of operating systems have become obsolete?

    Removing a function, even a function that doesn't do anything, even an undocumented function that doesn't do anything, is a dangerous endeavor. Suppose you have a program that links to the function, but just like Internet Explorer, it is clever and checks whether it is running on Windows NT before calling it. If you remove the useless function from shlwapi, then that program will fail to load, even though it never calls the offending function, and now you have an application compatibility problem on your hands.

    Since it's a small function that doesn't do anything, it's a lot less risky simply to leave the function in.

    Even though it doesn't do anything except fail.

Page 1 of 4 (34 items) 1234