April, 2007

  • The Old New Thing

    Code is read much more often than it is written, so plan accordingly

    • 53 Comments

    Design for readability.

    Even if you don't intend anybody else to read your code, there's still a very good chance that somebody will have to stare at your code and figure out what it does: That person is probably going to be you, twelve months from now.

    When I advised against the use of BOOL function parameters, one commenter pointed out that Intellisense shows you what the parameters are. Sure, that's a great help when you're writing the code, but you write the code only once. You read it a lot.

    An anonymous commenter pointed out that hovering over the offending function in the IDE shows the function declaration. While that may be true, it's still not a great solution. First, it means that you have to read code with your hand on the mouse. Second, it means that you can't skim code because you're going to hit a CreateEvent and then have to wait a little while for the tooltip to appear and then read and parse the tooltip and match the parameters up to what you have on the screen. This throws off your rhythm.

    Imagine if you had to read code that had gone through a ROT-13 filter. Sure, the IDE might help you by decoding the text under the cursor if you hover over it, but even instant help isn't fast enough.

    And finally, another commenter pointed out that this doesn't help you if you're reading code anywhere outside your IDE. It might be in a magazine, in a printout, in a bug report, on an overhead projector, on a web page, in a Usenet message, or in an email message. Good luck getting Intellisense to help you out there.

  • The Old New Thing

    On the enduring appeal of Walker, Texas Ranger

    • 11 Comments

    Conan O'Brien airs clips from Walker, Texas Ranger. The putative excuse for this is that, as a result of the merger of NBC with Universal Studios, he can air clips from the show without paying royalties. The real excuse, of course, is that the clips are just so unintentionally funny. This appears to be a recurring sketch on Conan, so a little hunting around will reveal plenty of other clips.

    This is, of course, not to be confused with Chuck Norris Facts or the Chuck Norris Fact Generator or the Young Chuck Norris sketch from Saturday Night Live...

  • The Old New Thing

    Why can't I display a tooltip for a disabled window?

    • 16 Comments

    Here's a question that floated past my field of view some time ago:

    When the mouse hovers over a disabled window, the tooltip associated with that window does not appear. Why is this? Why isn't this documented in MSDN?

    Actually, you already know the answer, and it is documented. You just have to connect the dots.

    When a window is disabled, it does not receive keyboard or mouse input. The documentation for EnableWindow says so in so many words, right in the first sentence.

    Next, how do tooltips know when to appear and disappear? Well, one way is to modify your window procedure so it takes all its input messages and forwards them to the tooltip control via the TTM_RELAYEVENT message. That way, the tooltip control knows where the mouse is and can show and hide itself accordingly. Alternatively, you can use the TTF_SUBCLASS flag to tell the tooltip control to subclass the tool window and grab the input itself. Both of these methods are also documented.

    Now put this all together. The tooltip control peeks at all the input destined for the tool window, either automatically via TTF_SUBCLASS or manually with TTM_RELAYEVENT. If the window is disabled, then it receives no input. Consequently, the tooltip control has no input to peek at and therefore doesn't know when to appear or disappear.

    This is also why you don't get tooltips for hidden windows and why you don't get tooltips when the mouse is captured to another window.

    So you see, you knew the answer all along. You just didn't realize it.

  • The Old New Thing

    Your chance to meet Raymond if you are near Palo Alto on the 23rd

    • 28 Comments

    There's been a slight change in plans. I will be in Palo Alto on April 23rd rather than April 20th. Not that anybody is affected by this beyond the folks at Microsoft's Silicon Valley Campus, since nobody else took me up on my offer. I guess I'm not as popular as I thought.

    Update 13-Apr-2007: Here's my schedule for April 23rd when I'm down San Jose way.

    9:00am – 10:00am: Brocade chat
    10:30am – 1:00pm: Google presentation + lunch chat
    1:30pm – 3:00pm: Apple chat
    3:30pm – 7:00pm: Microsoft SVC presentation + chat + dinner

    Now the term "presentation" is a bit of an overstatement. It's really just me telling a bunch of stories, but instead of sitting at a table with a bunch of people, I'll be standing in front of a room. Same stories, different audio system. I'll have a number of stories prepared, but I'm hoping some of the chatter will inspire other stories. (I won't do a coding presentation because, I mean really, a presentation on Win32 programming topics is bo-ring.)

    Extremely limited guest seating—we're talking one or two people—may be available at the Apple chat. The other appearances are closed-door. Dinner plans have yet to be settled, but I suspect that's your better bet. Contact me directly for details (if you haven't already).

  • The Old New Thing

    His lips are moving: In order to serve you better

    • 44 Comments

    Q: How do you know when a lawyer is lying?

    A: His lips are moving.

    This is of course a completely unfair and discriminatory joke.

    Many lawyers are women.

    Anyway, today I'm going to rant about the phrase "In order to serve you better." Whenever you hear this phrase, you are pretty much guaranteed that whatever follows will in fact not serve you better at all.

    When I bought tickets to see Real Madrid play against some Americans, the online ticket service gave me multiple options for receiving my tickets. I could have them mailed to me, or I could have the tickets sent to me electronically. And for some reason, there was a "convenience fee" for receiving electronic tickets, even though sending me electronic tickets costs them approximately one gazillionth of a penny†, whereas paper tickets cost them paper, handling, and postage. They are inviting me to pay more so they can save money. To maximize their revenues, they also put "(Recommended)" next to the electronic ticketing option and selected it by default.

    I can't believe they get away with this.

    It used to be that when you looked up somebody's office number in the address book at Microsoft, you got something like "9S/1044", which means "Room 1044 in the South wing of Building 9." These buildings are big, and knowing which half to start in can save you a lot of walking, especially in some buildings where the two wings are not always connected! For example, in Building 26 the north and south wings are connected only on the first two floors. If you want to get from the north wing of the third floor to the south wing, you have to go down a flight of stairs, then across, then up.

    But several years ago, they removed the wing designation from the address book. That same office is now listed as simply "9/1044". When I asked why they removed the wing designations, I was told, "We did this in order to serve you better. Many people were confused by it."

    I have yet to find any of those people who are being served better. Every single person I asked wanted the wing designations restored, too.

    Nitpicker's corner

    †A gazillion is not an actual number.

  • The Old New Thing

    Why does my thread pool use only one thread?

    • 32 Comments

    The thread pool is about reducing thread creating/termination overhead by consolidating work that would normally go onto separate threads into a small number of threads. In a sense, you shouldn't be surprised that the thread pool is using only one thread; instead, you should be happy!

    I switched to using the thread pool, and I'm finding that it's using only one thread. To demonstrate this, I wrote a test program that fires off a bunch of "work items" into the thread pool via QueueUserWorkItem. Each work item does some intensive computations. What I'm seeing is that they are all running serially on a single thread instead of running in parallel. Since I have a dual-processor machine, this leaves half of the computing capacity unutilized. If I create a separate thread for each "work item", then I get (not surprising) multiple threads and 100% CPU utilization. Why does my thread pool use only one thread?

    The purpose of the thread pool, as I noted above, was to reduce the overhead of creating and terminating threads by running multiple tasks on a thread. For example, suppose you have three short tasks, say 1ms each. If you put each one on its own thread, you have

    Task1.CreateThread, Task1.Run, Task1.EndThread
    Task2.CreateThread, Task2.Run, Task2.EndThread
    Task3.CreateThread, Task3.Run, Task3.EndThread

    Now suppose, for the purpose of this discussion, that creating and terminating a thread take 1ms each. if you create a separate thread for each task, you've spent 6ms on thread overhead and only 3ms doing actual work.

    What if we could run multiple tasks on a single thread? That way, the cost of creating and terminating the thread could be amortized over all the tasks.

    ThreadPool.CreateThread, Task1.Run, Task2.Run, Task3.Run, ThreadPool.EndThread

    Ah, now we have only 2ms of overhead for 3ms of work. Not great, but certainly better than what we had before. If we can pack more tasks into the thread pool, the fixed overhead of creating and terminating the thread becomes proportionally less.

    The thread pool is designed for handling a collection of brief tasks, since those are the tasks that would best benefit from thread pooling. If you had a task that ran for ten seconds, putting it on the thread pool wouldn't yield much in the way of savings; that 2ms overhead you avoided is just noise compared to your ten seconds of running time. (Last year, we saw another case of a series of tasks ill-suited to thread pooling.)

    As an accommodation for people who will put the occasional long-running task onto the thread pool (perhaps because it simplifies the program logic by treating everything as a work item), the thread pool allows you to give it a heads-up by passing the WT_EXECUTELONGFUNCTION flag. But that's not really what the thread pool is for. It's for quick-running tasks for which the overhead of creating a separate thread would be disproportionate to the work done by the task itself.

  • The Old New Thing

    Groundwork being laid for Vladimir Putin to run for his fourth term (out of a maximum of two)

    • 32 Comments

    The Russian constitution limits the president to two consecutive four-year terms, and Vladimir Putin is coming up on the end of his third. When he ran for his third term, he explained that his first term didn't count since it was served under the old constitution. This explanation appears to have been widely accepted because everybody reports that he is coming up on the end of his second term, not his third. (But I think it's funnier if you think of it as his third.)

    Now it appears that the groundwork is being laid for Putin to run for his fourth term. Out of a maximum of two.

    I'm not saying he does or doesn't deserve to be president for another term. (And he does say that he plans to step down, though he doesn't rule out the possibility of running again.) I'm just amused by the machinations involved in keeping him there.

    Former Moscow bureau chief for the Globe and Mail Marc MacKinnon chimes in with his thoughts (much better informed than mine).

  • The Old New Thing

    Why do operating system files still adhere to the old 8.3 naming convention?

    • 44 Comments

    Commenter Brian Reiter asks a duplicate of a question that was already submitted to the Suggestion Box: Darren asks why operating system† files still (for the most part) adhere to the old 8.3 naming convention.

    There are a few reasons I can think of. I'm not saying that these are the reasons; I'm just brainstorming.

    First, of course, the name of a DLL cannot change once it has been chosen, because that would break programs which linked to that DLL by its old name. Windows 95 did not require the system volume and user profile volume to support long file names, although that was certainly the case by default. Companies which used roaming profiles or redirected folders may have had a heavy investment in servers which did not support long file names. Therefore, all system files on Windows 95 had to conform to the 8.3 naming convention.

    I believe that Windows NT permitted the system volume to be a short-file-names-only FAT partition as late as Windows 2000. Therefore, any DLL that existed in the Windows 2000 era had to conform to the 8.3 naming convention.

    Starting in Windows XP, long file names became mandatory, and a few system files such as shellstyle.dll waded tentatively into the long file name world. (The .NET Framework folks jumped in with both feet with their managed DLLs, but notice that their unmanaged DLLs like mscoree.dll still conform to 8.3.) But the waters in this world can be treacherous for operating system components.

    First of all, you have to worry about the automatically-generated short name. Suppose the operating system setup program is copying the shellstyle.dll file, but there is already a file called shellstuff.dll. The short name for shellstuff.dll will probably be SHELLS~1.DLL, and therefore the short name for shellstyle.dll will likely be SHELLS~2.DLL. Now, this may not be a big deal, except that some programs like to hard-code a file's short name. (There are a lot of programs that assume that the Program Files directory is C:\PROGRA~1, for example.)

    Furthermore, you can create confusion if the same DLL is loaded by both its short and long names, since the loader treats them as distinct:

    #include <stdio.h>
    #include <windows.h>
    
    int __cdecl main(int argc, char **argv)
    {
     printf("%p\n", LoadLibrary("SHELLS~1.DLL"));
     printf("%p\n", LoadLibrary("SHELLSTYLE.DLL"));
     return 0;
    }
    

    If you run this program, you will get something like this:

    6F2C0000
    00340000
    

    Even though the two paths refer to the same DLL, the loader treats them as different, and you end up with two copies of the same DLL loaded into memory. Now things get confusing, since you now have two sets of global variables, and if two components both use SHELLSTYLE.DLL but one used the short name and the other the long name, things get exciting when those two components try to talk about what they think is the same thing.

    It's like that time when I was a child and our family took a trip to Disneyland. Our parents put my brother and me on the gondola ride, and upon arrival at the other end, we were to go to the Autopia ride which was right next door. The plan was that our parents would meet us at the exit to Autopia. When my brother and I exited Autopia, we expected our parents to be waiting there for us, but they were nowhere to be seen. Sticking to the plan, we waited patiently for our parents to arrive. We sat there for what seemed like two hours (but which was probably much less), until eventually we decided that my brother would stay put and I would go looking around, at which point it didn't take long for me to find my father, who was walking around looking for us.

    What went wrong? Well, the problem was that the map of Disneyland showed Autopia, but what the map didn't say was that there were two Autopia rides (and therefore two Autopia exits) right next to each other. My brother and I were waiting by one exit, and our parents were waiting by the other. Each of us thought the other party was simply late.

    Similarly, if a DLL goes by multiple names, you can end up with two copies of it loaded into the process, with different components talking about different copies, unaware that they are talking about different things.

    And one final reason I can think of for sticking with 8.3 file names for operating system DLLs is simply, "Well, that's the way we've always done it. All the problems with 8.3 names are well-understood and under control. If we switched to long file names, we'd end up discovering a whole new set of problems. Why mess with something that works if it isn't broken?"

    Better the devil you know.

    Exercise: Why is it okay for the .NET Framework to use long file names for their managed DLLs?

    Nitpicker's Corner

    †s/operating system/Windows operating system/. Apparently nothing is obvious from context any more.

Page 4 of 4 (38 items) 1234