March, 2007

  • The Old New Thing

    What do the colors in the elevation dialog mean?

    • 73 Comments

    On Windows Vista with User Account Control enabled, when you right-click a program and select Run as Administrator, the elevation prompt contains a particular snippet of warning text and a corresponding color-coding. Here are what the four colors mean.

    Windows needs your permission to continue
    A blue-green banner indicates that the program is a Windows operating system component. Remain calm.
    A program needs your permission to continue
    A gray banner indicates that the program has been signed but is not part of Windows. Be cautious.
    An unidentified program wants access to your computer
    A yellow banner indicates that the program's identity cannot be digitally confirmed. Be suspicious.
    This program has been blocked
    A red banner indicates that the program has been blocked from running. Run away.

    You can learn about the philosophy behind UAC in this Channel9 interview.

    Pre-emptive snarky comment: "UAC sucks!"

    The purpose of this entry is not to discuss whether UAC is a good idea or not. I'm just trying to help by providing information on what the colors mean. This is one of the entries that I was afraid to write. On its own, it's useful information, but I anticipate a torrent of nasty comments from people who see it as an opportunity to start flaming. I have other tips and stories related to controversial topics; this is a trial balloon entry. If I get a bad experience from this entry, I'll delete the others. Just like how I deleted all my stories about Bob.

    Update: Okay, just to make it clear (since I'm told that people don't read other comments before posting their own). I did not work on UAC. If you ask me a question about its design or how it works, the answer will be "I don't know." That's why I included a link to a talk from the people who actually know something about it.

  • The Old New Thing

    On the effect of dandruff on climate

    • 4 Comments

    The Improbable Research blog alerted me to a news report on the effect of dandruff and other cellular material on climate (full report).

  • The Old New Thing

    How to talk like Marketing: The awareness space

    • 13 Comments

    The great thing about Marketing is that you get to use words and phrases that normal human beings never use. Here's an example from over a decade ago:

    XYZ fit the installed base of web browsers we were targeting, and worked well in an awareness space.

    I have no idea what an "awareness space" is.

    The punch line? This sentence came from a person whose title was "Director of Communication"!

  • The Old New Thing

    The buffer size parameter to GetFileVersionInfo is the size of your buffer, no really

    • 30 Comments

    The GetFileVersionInfo function takes a pointer to a buffer (lpData) and a size (dwLen), and that size is the size of the buffer, in bytes.

    No really, that's what it is.

    The application compatibility folks found one popular game which wasn't quite sure what that dwLen parameter meant. The programmers must have thought it meant "The size of the version resources you want to load" and called it like this (paraphrased):

    void CheckFileVersion(LPCTSTR pszFile)
    {
     BYTE buffer[1024];
     DWORD dwHandle;
     DWORD dwLen = GetFileVersionInfoSize(pszFile, &dwHandle);
     if (GetFileVersionInfo(pszFile, dwHandle, dwLen, buffer)) {
      ...
     }
    }
    

    "Gosh, the GetFileVersionInfo function wants to know how big the version info is, so we need to call GetFileVersionInfoSize to find out!" they must have thought.

    This code worked great... for a while. It was checking the file version of the video driver. (My guess is that they were trying to detect specific video drivers so they could work around bugs in them or take advantage of driver-specific features.) But if you had a video driver whose version resource needed more than 1024 bytes of space, the program crashed with stack corruption.

    I don't know whether the Windows Vista application compatibility folks decided that it was worth fixing this program's bug, since it occurred even on Windows XP. If so decided, the fix would have been fairly straightforward. Once the program was detected, we would just have had to take the value the program passed as dwLen and modify it according to the simple formula

    dwLen = min(dwLen, 1024);
    

    before doing the real work of loading the version information.

    For those playing along at home, by the way, the correct code would go something like this:

    void CheckFileVersion(LPCTSTR pszFile)
    {
     DWORD dwHandle;
     DWORD dwLen = GetFileVersionInfoSize(pszFile, &dwHandle);
     if (dwLen) {
      BYTE *pBuffer = (BYTE*)malloc(dwLen);
      if (pBuffer) {
       if (GetFileVersionInfo(pszFile, dwHandle, dwLen, pBuffer)) {
        ...
       }
       free(pBuffer);
      }
     }
    }
    

    (Use your favorite memory allocation technique instead of malloc and free.)

  • The Old New Thing

    The social skills of a thermonuclear device, part 4

    • 27 Comments

    Last summer, one of my colleagues thought it would be fun to have an informal "lunch chat with Raymond" as a special treat for our summer interns. One of the interns reacted to the invitation a bit unexpectedly, asking meekly, "Is he going to yell at us?"

  • The Old New Thing

    Why are there both TBSTYLE_EX_VERTICAL and CCS_VERT?

    • 13 Comments

    There are two ways to make a vertical toolbar. You can use the common CCS_VERT style, or you can use the TBSTYLE_EX_VERTICAL extended style which is specific to the toolbar. Why are there two ways of doing the same thing?

    Because we messed up.

    Whoever created the TBSTYLE_EX_VERTICAL extended style didn't realize that there was already a perfectly good way of specifying a vertical toolbar (namely, CCS_VERT).

    What's worse, some vertical behavior is controlled by CCS_VERT and some by TBSTYLE_EX_VERTICAL. So if you want a vertical toolbar, you probably want to set both styles to cover all your bases on Windows XP.

    Unfortunately, the story doesn't get any better. Once this mistake was discovered, work was done to try to get the two styles in sync, so that setting one automatically set the other. The idea was to ensure that everybody got consistent behavior instead of getting half-and-half if you, say, turned on CCS_VERT and forgot to turn on TBSTYLE_EX_VERTICAL. But this was itself a failure, because there were some programs that let the two styles fall out of sync on purpose because they liked the half-and-half behavior.

    It's a mess. We're sorry.

    Pre-emptive snarky comment: "This is why Windows sucks."

  • The Old New Thing

    Microspeak: Calibration

    • 38 Comments
    There is nothing wrong with your television set.
    Do not attempt to adjust the picture. ...
    We will control the horizontal.
    We will control the vertical.
    - The Outer Limits

    Today's Microspeak is the word calibration. It used to mean the act of adjusting a piece of measuring equipment against a known standard so that it can perform its job accurately. For example, before reading student essays, I go through a calibration exercise, wherein all the readers are given a handful of essays of varying quality and discuss what grade each one deserves so that our scores will be consistent with each other.†

    And then I see the word used in a way that convinces me that I don't know what it means any more. Consider this sentence:

    I would like to get calibration on that individual from those who know him.

    How do you "get calibration"? What is this person trying to say, and why won't he use plain English?

    Nitpicker's corner

    †s/consistent/more consistent/. Obviously, since there is a human element involved, the scores cannot be absolutely consistent.

  • The Old New Thing

    The publicity machine continues: A chat with Scott Hanselman and Hanselminutes

    • 11 Comments

    Scott Hanselman let me know he was going to be in town, and after some negotiation with the company PR department (who probably get the massive heebie-jeebies from this whole blog thing), I was able to accept his invitation to appear on his weekly podcast, HanselMinutes. We sat down for a little chat, and a few weeks later, I became Show #56.

    I haven't had the nerve to listen to it myself. I hope I came off okay.

    In other self-promotion news (did I mention yet that I wrote a book?), it looks like I will be in Palo Alto on April 21 for a family event, and I'll likely spend the 20th visiting Microsoft's Silicon Valley Campus. If you'd like me to pay a visit to your user group or whatever, let me know.

  • The Old New Thing

    Passing by address versus passing by reference, a puzzle

    • 29 Comments

    Commenter Mike Petry asked via the Suggestion Box:

    Why can you dereference a COM interface pointer and pass it to a function with a Com interface reference.

    The call.

    OutputDebugString(_T("IntfByRef::Execute - Begin\n"));
    BadBoy badone;
    CComPtr<IDoer> Doer;
    Doer.CoCreateInstance(CLSID_Doer, NULL, CLSCTX_INPROC_SERVER);
    
    // created a raw pointer - maybe the
    // smart pointer was effecting it some how.
    IDoer* Doer2;
    Doer.CopyTo(&Doer2);
    
    badone.stupid_method(*Doer2);
    Doer2->Release();
    // no still works.
    

    The function called.

    void stupid_method(IDoer& IDoerRef)
    {
     IDoerRef.Do();
     CComQIPtr<IDispatch> WatchIt(&IDoerRef);
    
     if( WatchIt )
      OutputDebugString(_T("QI the address of the ")
                        _T("ref works - this is weird\n"));
     else
      OutputDebugString(_T("At least trying to QI the ")
                        _T("address of the ref fails\n"));
    }
    

    I found some code written like this during a code review. It is wrong but it seems to work.

    You already know the answer to this question. You merely got distracted by the use of a COM interface. Let me rephrase the question, using an abstract C++ class instead of a COM interface. (The virtualness isn't important to the discussion.) Given this code:

    class Doer {
     public: virtual void Do() = 0;
    };
    
    void caller(Doer *p)
    {
     stupid_method(*p);
    }
    
    void stupid_method(Doer& ref)
    {
     ref.Do();
    }
    

    How is this different from the pointer version?

    void caller2(Doer *p)
    {
     stupid_method2(p);
    }
    
    void stupid_method2(Doer *p)
    {
     p->Do();
    }
    

    The answer: From the compiler's point of view, it's the same. I could prove this by going into what references mean, but you'd just find that boring, but instead I'll show you the generated code. First, the version that passes by reference:

    ; void caller(Doer *p) { stupid_method(*p); }
    
      00000 55               push    ebp
      00001 8b ec            mov     ebp, esp
      00003 ff 75 08         push    DWORD PTR _p$[ebp]
      00006 e8 00 00 00 00   call    stupid_method
      0000b 5d               pop     ebp
      0000c c2 04 00         ret     4
    
    ; void stupid_method(Doer& ref) { ref.Do(); }
    
      00000 55               push    ebp
      00001 8b ec            mov     ebp, esp
      00003 8b 4d 08         mov     ecx, DWORD PTR _ref$[ebp]
      00006 8b 01            mov     eax, DWORD PTR [ecx]
      00008 ff 10            call    DWORD PTR [eax]
      0000a 5d               pop     ebp
      0000b c2 04 00         ret     4
    

    Now the version that passes by address:

    ; void caller2(Doer *p) { stupid_method2(p); }
    
      00000 55               push    ebp
      00001 8b ec            mov     ebp, esp
      00003 ff 75 08         push    DWORD PTR _p$[ebp]
      00006 e8 00 00 00 00   call    stupid_method2
      0000b 5d               pop     ebp
      0000c c2 04 00         ret     4
    
    ; void stupid_method2(Doer *p) { p->Do(); }
    
      00000 55               push    ebp
      00001 8b ec            mov     ebp, esp
      00003 8b 4d 08         mov     ecx, DWORD PTR _p$[ebp]
      00006 8b 01            mov     eax, DWORD PTR [ecx]
      00008 ff 10            call    DWORD PTR [eax]
      0000a 5d               pop     ebp
      0000b c2 04 00         ret     4
    

    Notice that the code generation is identical.

    If you're still baffled, go ask your local C++ expert.

    Mind you, dereferencing an abstract object is highly unusual and will probably cause the people who read your code to scratch their heads, but it is nevertheless technically legal, in the same way it is technically legal to give a function that deletes an item the name add_item.

  • The Old New Thing

    The wisdom of seventh graders and you: Design a course

    • 70 Comments

    I'm out today to volunteer with grading student essays. The topic the students were given is one that I suggested: "You have been chosen to design a new elective for your school. Describe what it would be."

    In a few weeks, you'll learn what the students wrote, but my question for you is what you would propose in your essay. You can answer the question with the wisdom of adulthood (i.e., what course you would design for seventh graders), or, more challenging, you can describe what sort of course you would have designed if you were given this assignment as a twelve-year-old. (Please specify which category you're submitting your entry to.)

    At the end of the day, I'll update this entry with my answers.

    Update: When I was in seventh grade, I would have wanted an elective in radio and television broadcasting and production. With the hindsight of adulthood, I would propose a course on "basic life skills": From issues such as time management and personal finances (e.g. using funny-money credit cards to experience the consequences of missing a payment) to facts of life like "show up for work on time, no excuses", as well as small skills like how to make change when you don't have a calculator to give you the answer. Though on reflection, this might be more suited to high schoolers.

Page 1 of 4 (39 items) 1234