July, 2009

  • The Old New Thing

    The guerilla wedding

    • 11 Comments

    When two of my friends were getting married (to each other), there was of course a lot of effort spent on finding the right wedding location. To relieve the tension, when we got together, we would amuse ourselves by coming up with guerilla wedding locations, which was our term for surreptitiously holding a wedding ceremony at a location without the site owner's knowledge. Everybody would converge on the designated location, wait for the secret signal, and then spontaneously assemble for a wedding ceremony, wrapping it all up before anybody else knew what happened. Here are some ideas in the Seattle area we came up with:

    Even now, with the wedding planning a dim memory, when we find a particularly nice location, we still find ourselves turning to each other and saying, "guerilla wedding."

  • The Old New Thing

    If you wished a language supported the preprocessor, you know, you can fix that

    • 24 Comments

    A customer had the following question about the message compiler, something that I had noted almost nobody uses. Well how do you do, we found somebody who actually uses it. Anyway, the question went like this (paraphrased, as always):

    Can I use symbolic constants in my .mc file? For example, I have a message file that goes like this:

    SymbolicName=ERROR_XYZ_TOO_LARGE
    The XYZ parameter cannot exceed 100.
    .
    
    SymbolicName=ERROR_ABC_TOO_SMALL
    The ABC parameter must be at least 1.
    .
    
    SymbolicName=ERROR_CANT_COMBINE_ABC_WITH_XYZ
    You cannot specify values for both ABC and XYZ.
    .
    

    I have symbols defined in a header file #define MINIMUM_ABC_VALUE 1 and #define MAXIMUM_XYZ_VALUE 100 that I, of course, have to keep in sync with the error messages. One way to do this is to change the messages:

    SymbolicName=ERROR_XYZ_TOO_LARGE
    The XYZ parameter cannot exceed %1!d!.
    .
    
    SymbolicName=ERROR_ABC_TOO_SMALL
    The ABC parameter must be at least %1!d!.
    .
    

    And in my function that prints error messages, I can insert these magic parameters:

    error = DoMyThing(...);
    
    if (error != ERROR_SUCCESS) {
     switch (error) {
     case ERROR_ABC_TOO_SMALL:
      Insertion = MINIMUM_ABC_VALUE;
      break;
     case ERROR_XYZ_TOO_LARGE:
      Insertion = MAXIMUM_XYZ_VALUE;
      break;
     case ERROR_CANT_COMBINE_ABC_WITH_XYZ:
      Insertion = 0; // not used
      break;
     ... repeat for other error messages...
     }
     DWORD_PTR Parameters[1] = { Insertion };
    
     FormatMessage(FORMAT_MESSAGE_ARGUMENT_ARRAY ...
         ..., error, ..., (va_list*)&Parameters)...
    }
    

    This is obviously a rather high-maintenance approach. Is there some way I could just write, say,

    SymbolicName=ERROR_XYZ_TOO_LARGE
    The XYZ parameter cannot exceed {MAXIMUM_XYZ_VALUE}.
    .
    
    SymbolicName=ERROR_ABC_TOO_SMALL
    The ABC parameter must be at least {MINIMUM_ABC_VALUE}.
    .
    

    and have the message compiler do the substitution? It would be great if it could even take the values from my header files.

    This is a case of standing right next to the answer and not even realizing it.

    There's no law that says that you're not allowed to use any other tools. It so happens that the preprocessor is a handy tool. If you want the preprocessor to run over your message files before they go into the message table, then why not run the preprocessor over your message files before they go into the message table?

    #include "qqlimits.h" // pretend the program's name is "qq"
    
    ...
    
    SymbolicName=ERROR_XYZ_TOO_LARGE
    The XYZ parameter cannot exceed MAXIMUM_XYZ_VALUE.
    .
    
    SymbolicName=ERROR_ABC_TOO_SMALL
    The ABC parameter must be at least MINIMUM_ABC_VALUE.
    .
    
    SymbolicName=ERROR_CANT_COMBINE_ABC_WITH_XYZ
    You cannot specify values for both ABC and XYZ.
    .
    

    Give this file a name like, say, qq.mcp, and add a rule to your makefile:

    qq.mc: qq.mcp qqlimits.h
      cl /EP qq.mcp >qq.mc
    

    Make your changes to qq.mcp, and when you build, the makefile will preprocess it and generate the qq.mc file, which you can then compile with the message compiler just like you were doing before.

  • The Old New Thing

    Changes to the the 2009/2010 Seattle Symphony subscription season, part 2

    • 0 Comments

    The Seattle Symphony made a large number of changes to their 2009/2010 program line-up. I've updated the 2009/2010 Seattle Symphony subscription season at a glance accordingly.

    The Brahms Variations on a Theme by Hadyn, the Brahms/Schoenberg Piano Quartet in g minor, and the Shostakovich Symphony #15 moved to different dates, and a large number of substitutions or single-piece additions/subtractions were made. The concert for the week of October 30 was cancelled outright; ticket-holders will be issued tickets for the week of May 6 instead.

  • The Old New Thing

    Your debugging code can be a security hole: Contest tickets

    • 27 Comments

    Last year, the Microsoft cafeterias ran a promotion which involved scratch-off tickets and prizes ranging from a free bagel to a new Zune to free airplane tickets. But it turns out that the people who ran the contest left some debugging code behind that became a security hole.

    As people compared notes on what they did or didn't win, they noticed that the tickets all looked identical save for the scratch-off area (naturally) and some tiny numbers printed in the corner of the back of the card. After some study, it became clear that all the losing tickets had a code that ended in 01, all the tickets for a free bagel ended in 18, and so on. If you went to the contest rules and regulations Web site, you'd find the legally mandated odds of winning disclosure, and the table just so happened to have no prize as the first item in the table and free bagel as the eighteenth. Further comparisons with other winning tickets confirmed that you could tell ahead of time what prize you were going to win by just looking at the last two digits of the number printed on the back of the card.

    This is another example of how your debugging code can be a security hole. In this case, the code printed on the backs of the cards were probably added for quality control purposes, so that the contest managers could ensure that the right number of winning tickets were printed and so that the "big ticket" prizes would be evenly distributed among the participating cafeterias.

    But it also meant that everybody participating in the contest knows which are the winning tickets.

  • The Old New Thing

    I saw a fascinating documentary about bugs

    • 7 Comments

    In the September 20, 2007 Dilbert comic, Dilbert says to his date, "I saw a fascinating documentary about bugs."

    A Year in the Life of Ants.

  • The Old New Thing

    Microspeak: Whale Boy

    • 9 Comments

    Today is the tenth anniversary of Windows Live Messenger. My colleague Danny Glasser provides some history behind the product, and you can watch a tenth anniversary celebration video created for the occasion. And thus is inspired today's Microspeak: Whale Boy.

    Whale Boy is the nickname for the pawn-shaped Messenger buddy icon. His normal state is green, but he changes color or picks up a piece of flair to indicate various changes in status, such as busy or away.

    I don't know the etymology of the term, but I suspect it came from his somewhat rotund appearance.

    Sample usage (which I made up just now; not from an actual document): "Why don't we light up Whale Boy when the user regains connectivity?"

    Bonus Microsoft trivia: At timecode 3:40 in the video (spoiler alert!) Steve Liffick presents Whale Boy with a strange glass object. That is the Microsoft ten-year service award. Stick around for 25 years and collect the entire set!

  • The Old New Thing

    Proto-Microspeak: Coceptualize

    • 35 Comments

    Many years ago, to see whether anybody was paying attention, a colleague and I slipped the made-up word "coceptualize" into a document.

    Nobody said a thing.

    Either nobody read that part of the document, or they did and thought it was a real word.

  • The Old New Thing

    Why was MoveTo replaced with MoveToEx?

    • 42 Comments

    Commenter Ulric asks, "Where did MoveTo(HDC, int, int) go?"

    Back in the 16-bit days, the function to move the current point was called MoveTo, and its return value was a DWORD which encoded the previous position, packing two 16-bit coordinates into a single 32-bit value. As part of the transition to 32-bit Windows, GDI switched to using 32-bit coordinates instead of the wimpy 16-bit coordinates of old. As a result, it was no longer possible to encode the original position in a single DWORD. Something new had to be developed.

    That new thing was the MoveToEx function. Instead of returning a single DWORD, it accepted a final parameter which received the previous coordinates. If you didn't care about the previous coordinates, you could just pass NULL. All of the GDI functions which used to pack two 16-bit coordinates into a single DWORD got Ex-ified in this way so they could accommodate the new 32-bit coordinate system.

    But why did the old MoveTo function go away? Why not keep it around for source code compatibility?

    I find this an interesting question, since most people seem to think that maintaining source code compability between the 32-bit and 64-bit versions of Windows was an idea whose stupidity rivals prosecuting a land war in Asia. (If we had followed this advice, people would just be asking, why did you replace WinExec with the much harder-to-use CreateProcess?) By the same logic, source code compatibility between 16-bit and 32-bit Windows is equally absurd. According to these people, porting 16-bit code to to 32-bit Windows is the best time to introduce these sorts of incompatibilities, in order to force people to rewrite their programs.

    Anyway, the reason we lost MoveTo was that there was no way to return 64 bits of information in a 32-bit integer. Now it's true that in many cases, the caller doesn't actually care about the previous position, but of course the MoveTo function doesn't know that. It returns a value; it doesn't know whether the caller is going to use that return value or not.

    I guess one way out would have been to change the return value of MoveTo to void. That way, people who didn't care about the return value would still compile, while people who did try to use the return value would get a compile error and have to switch to MoveToEx.

    Yeah, I guess that could've been done, but you could also have done that yourself:

    #define MoveTo(hdc, x, y) ((void)MoveToEx(hdc, x, y, NULL))
    

    I find it interesting that most people who write their own MoveTo macro don't use the (void) cast. In most cases, this is a mistake in porting from 16-bit Windows. (I can tell because the macro is mixed in with a bunch of other porting macros.) However, in other cases, it could be intentional. The authors of the macro may simply not have known about the old 16-bit days and simply expected their macro to be used as if it were prototyped as BOOL MoveTo(HDC, int, int).

    These people will probably be baffled if they run across any actual 16-bit Windows code that tried to extract the high word from the return value of MoveTo. "Why are you extracting the high word from a BOOL?"

    Historical exercise: Instead of adding a new parameter, why not just make MoveToEx return an __int64?

  • The Old New Thing

    The disembodiment of DIBs from the DIB section

    • 4 Comments

    So far this week, we've separated the DIB metadata (BITMAPINFO) from the pixels of a DIB section. But there's really no need for the DIB section at all! As long as you have the pixels and the metadata, you can draw bits.

    We demonstrate this by drawing a rather stupid-looking bitmap onto the screen, but doing so without the use of HBITMAPs at all! Start with a brand new scratch program and make these changes:

    const BYTE g_rgbPixels[16][8] = {
     { 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD },
     { 0xDD, 0xDD, 0xD0, 0x00, 0x00, 0xDD, 0xDD, 0xDD },
     { 0xDD, 0xD0, 0x01, 0x11, 0x11, 0x00, 0xDD, 0xDD },
     { 0xDD, 0x01, 0x11, 0x11, 0x11, 0x11, 0x0D, 0xDD },
     { 0xD0, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0xDD },
     { 0xD0, 0x11, 0x00, 0x00, 0x00, 0x01, 0x10, 0xDD },
     { 0x01, 0x11, 0x09, 0x99, 0x99, 0x01, 0x11, 0x0D },
     { 0x01, 0x11, 0x09, 0x99, 0x99, 0x01, 0x11, 0x0D },
     { 0x01, 0x11, 0x09, 0x99, 0x99, 0x01, 0x11, 0x0D },
     { 0x01, 0x11, 0x09, 0x99, 0x99, 0x01, 0x11, 0x0D },
     { 0x01, 0x11, 0x09, 0x99, 0x99, 0x01, 0x11, 0x0D },
     { 0xD0, 0x11, 0x00, 0x00, 0x00, 0x01, 0x10, 0xDD },
     { 0xD0, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10, 0xDD },
     { 0xDD, 0x01, 0x11, 0x11, 0x11, 0x11, 0x0D, 0xDD },
     { 0xDD, 0xD0, 0x01, 0x11, 0x11, 0x00, 0xDD, 0xDD },
     { 0xDD, 0xDD, 0xD0, 0x00, 0x00, 0xDD, 0xDD, 0xDD },
    };
    
    struct BITMAPINFO16 {
     BITMAPINFOHEADER bmiHeader;
     RGBQUAD bmiColors[16];
    } g_bmi = {
     { sizeof(g_bmi.bmiHeader), // biSize
                            16, // biWidth
                            16, // biHeight
                             1, // biPlanes
                             4, // biBitCount
                        BI_RGB, // biCompression
                             0, // biSizeImage
                             0, // biXPelsPerMeter
                             0, // biYPelsPerMeter
                            16, // biClrUsed
                            16, // biClrImportant
     },
     {
      { 0x00, 0x00, 0x00, 0x00 },// bmiColors[0]
      { 0x80, 0x00, 0x00, 0x00 },// bmiColors[1]
      { 0x00, 0x80, 0x00, 0x00 },// bmiColors[2]
      { 0x80, 0x80, 0x00, 0x00 },// bmiColors[3]
      { 0x00, 0x00, 0x80, 0x00 },// bmiColors[4]
      { 0x80, 0x00, 0x80, 0x00 },// bmiColors[5]
      { 0x00, 0x80, 0x80, 0x00 },// bmiColors[6]
      { 0xC0, 0xC0, 0xC0, 0x00 },// bmiColors[7]
      { 0x80, 0x80, 0x80, 0x00 },// bmiColors[8]
      { 0xFF, 0x00, 0x00, 0x00 },// bmiColors[9]
      { 0x00, 0xFF, 0x00, 0x00 },// bmiColors[10]
      { 0xFF, 0xFF, 0x00, 0x00 },// bmiColors[11]
      { 0x00, 0x00, 0xFF, 0x00 },// bmiColors[12]
      { 0xFF, 0x00, 0xFF, 0x00 },// bmiColors[13]
      { 0x00, 0xFF, 0xFF, 0x00 },// bmiColors[14]
      { 0xFF, 0xFF, 0xFF, 0x00 },// bmiColors[15]
     }
    };
    
    void
    PaintContent(HWND hwnd, PAINTSTRUCT *pps)
    {
     StretchDIBits(pps->hdc, 0, 0,
                   g_bmi.bmiHeader.biWidth*4,
                   g_bmi.bmiHeader.biHeight*4,
                   0, 0,
                   g_bmi.bmiHeader.biWidth,
                   g_bmi.bmiHeader.biHeight,
                   g_rgbPixels, (BITMAPINFO*)&g_bmi,
                   DIB_RGB_COLORS, SRCCOPY);
    }
    

    We are drawing a bitmap without using an HBITMAP! The technique is the same one we've been using all week: Building a BITMAPINFO and using it to guide the interpretation of a chunk of memory containing pixels. Just to make things easier to see, I magnified the image, but the point is the same.

    Okay, now let's look at the limitations and caveats of this technique. First, of course, is that this works only when the memory contains the source bitmap for a BitBlt or StretchBlt operation. It's nice when you have a bunch of bitmaps that you only intend to draw from, but you can't use this technique to draw into a chunk of memory. For that, you'll want to create a DIB section and draw into that.

    Another problem with this technique is that it doesn't play friendly with remote desktops, one of those Windows programming taxes. After all, pumping a chunk of pixels to the screen is the logical equivalent of a BitBlt of a bitmap nobody has ever seen before. You've got pixels just coming out of nowhere. There's nothing to cache since there is no HBITMAP to associate the pixels with. On remote desktops, it's probably okay to use this technique for small bitmaps (like ours) where the cost of sending the pixels is insigificant, or if your render target is not the screen (for example, if you are rendering to an off-screen bitmap because you're doing some image manipulation behind the scenes).

  • The Old New Thing

    Caption contest: The pinball machine: Results

    • 13 Comments

    It's been quite a while, but a winner in the caption contest has been selected and the prize finally reached its destination. (Mostly due to procrastination on my part. Don't blame the postal service.)

    The winner is Scott from Australia with his entry

    Only 5,000 more referrals until MULTIBALL

    Even though it's kind of low-brow, it made me laugh spontaneously.

    For his efforts, Scott wins a deluxe prize package consisting of

    • Exchange 2010 laptop skin
    • I'm a PC sticker and yoyo
    • Windows 7 stress ball
    • Assorted logo pens (Microsoft, Xbox 360, Microsoft Office)
    • TSA-approved Microsoft travel lock (so he can travel to our country should he be so inspired)
    • Miscellaneous historical items from the wayback drawer
      • Windows Me pen
      • Microsoft Bob lapel pin
      • Microsoft 20th anniversary kazoo
      • Temporary tattoos: Windows 2000, Windows 95, OLE (who knew they even had a logo!), Microsoft Visual Tools, MSN, Microsoft BackOffice.

    Here's Scott's acceptance speech:

    I'd like to thank all the letters that made the caption possible - the O, the N, the R, and especially the L - that little guy really pulled his weight. And thank you to the 1990's, for coming up with blogs, so that I could one day win a caption contest.
Page 2 of 5 (42 items) 12345