January, 2007

  • The Old New Thing

    The wisdom of sev^H^H^Heighth graders: It was not just white people who were helped by Martin Luther King

    • 26 Comments

    (Today is the birthday of the famed civil rights leader, the first time since 2001 that the federal holiday coincides with the correct historical date. It seemed an auspicious date to return to the time machine essay.)

    The eighth grade students were given the same in-class writing assignment as the seventh graders, with the same ground rules, I took two days off from work to help read those essays like I did with the seventh grade essays. (What can I say. I volunteer for strange things.)

    When I started reading the essays, I immediately noticed the difference one year makes in the quality of writing. The eighth grade essays are better put-together, the ideas more fully fleshed-out. But that doesn't mean that every single essay is a work of art. Here are selections from some essays that one might call the whey of the crop.

    Introductions

    It's clear that these students have been taught the importance of having an introduction that establishes the topic of the essay. But some students have taken the formula a bit too literally.

    • In this letter I will tell you where, when, and why I would go.
    • Come join me in my adventure of words as I explain where I go, when I would go and why I would go there.
    • You explained to me earlier that I had to write you a multi-paragraph letter to you explaining where, when and why I would like to go. Here it goes.
    • Well I am writing you this to tell you.

    It doesn't hurt to flatter the teacher.

    • I have to say, this is probably your hugest success in your history of teaching here at X Middle School.
    • Wow. You created a time machine. How'd you do that?
    • An unaccountable amount of thanks! Sincerely X
    • Your going to love the time machine I built, it's on of a kind! [This student is clearly management material, taking credit for somebody else's work.]

    Other students took the opportunity to reflect on the nature of the time machine itself.

    • I have longed to do this traveling trip for some time.
    • I cannot possibly express my feelings of joy through paper!
    • I think thirteen years old, is too young to have such an incredulous offer thrown upon you.

    A sense of scale

    • I would want to go to about 200 B.C. where all of the dinosaurs weren't that vicious.
    • On TV they have shows that show how the 80s were. These shows are a lot better then my parents storys.
    • If my science teacher gave me a time machine I will go back in time to the 1800s. Why? Because it will show me more things that my dad and mom went through.
    • It would be Washington D.C. in the year 3006... we might have a new president.
    • [At age 25] I would hopefully be out of the house by then- & would finally be able to drive

    People from the past were so stupid

    • This is an ideal choice for me because cavemen are stupid, and there are all kinds of ways to control and manipulate idiots.
    • The treasures my cavemen servants would bring me would be spectacular.
    • With the knologe that I have now even at 14 I am smarter than most of the people in England [in the year 1200].

    Travelling to the past

    • Could you bring people back from the dead? If you could I would get the greatest mines.
    • ... but to see everybody dressed like this, I think I might pass out of bad fashion disease.
    • But most of their dresses are just down right poofy! And sometimes I wonder how they walk in them.
    • The most exciting event to see would be the writing of the Mayflower Compact.
    • ... head to the colonies about 1600-1700's. ... I would show off the hover skate board & hover bike, & try to convince them that I am a new born god.
    • I will need to find the time of day that he [Abraham Lincoln] died so I can properly time my heroic halting of historic events.
    • ... until Hitler committed sucide wich oveyosley led to his downfall. [Not many people recover from suicide.]
    • First, many items and services that are now excruciatingly overpriced were a bargain back in the 1950's.
    • She made them write their names on a puper.
    • But in the 1950's some of the greatest musicians of all time were creating a cornucopia of music created with mastery and skill. [Well, a cornucopia is technically a horn...]
    • And it was not just white people who were helped by Martin Luther King!
    • I've only heard abaout what [my parents] wore to school and it doesn't sound too good! [I doubt they think much of what you wear to school either, sweetie.]
    • In the 70's they had great bands such as Pearl Jan, The Beatles, AC/DC, and Bon Jovi. [One out of four ain't bad.]
    • My hope on this adventure is to learn the correct way to dance the disco. This is because now I only know that you point your finger in the air and shake your booty.
    • The Titantic first set sail in 1979.
    • I would go to Dr. Stephen Hawking because I could help him improve his work. [With your help, he might become smart.]
    • To us right now, $2.86 per lb. of gas is a lot.
    • I never got to do any of these things with [my grandmother], let alone see her; which was nearly every 1 or 2 years. [This is a meaning of the word "never" with which I was previously unfamiliar.]
    • I will visit the famous Britch Mussium when I visit London.

    Life in the future

    • If I go into the future I could see who I end up marring.
    • The thing I most want to know is who will be my wife?
    • Maybe the robots will feel oppressed and grab torches and pick forks and run all the humans out of town... or the planet!
    • I would go to the year 3000 because 3000 seems like a futury time.
    • [visiting one future self] What if I get job or even killed!
    • Sadly, my house will be turn down and rebuilt for richer people to live in.
    • I imagine new sports like a sport that combines every sport into one huge sport. [What about the sport that includes all sports that don't include themselves?]
    • Later as the years pass people will be teleported to school or work.
    • In 2122, will people have short, long, curly, straight or be balled?
    • Same people and environmentalists predict...
    • We might have... toasters that sing pop goes your ego.
    • Also, I have many ideas about how to become extinct.
    • Would there be a devise where you could clone yourself so you wouldn't have to go to a boring event.

    Religious-themed

    • I would get to see God in the flesh doing maricles!
    • I would like to see the Last Supper if I can get in!
    • To see him die on the cross and rise from the dead would be an uncanning experience.
    • I would go to Herisalem one month before the Crusaification of Christ. The reason I would go the Jerusalem, would be to stop the greatest sin man has ever made. [In other words, you want to destroy the foundation of your religion.]

    Spelling lightning round

    • If there were title waves I might be able to prevent them in the past.
    • Urothain wheels were made out of a certain type of oil.
    • I could stop the man who found the gold to be gin with.
    • differen't [I've never seen an apostrophe used that way before.]
    • Being there would make me feel as if I am apart of history.
    • I pounder about all these things...
    • ...the midevil ages...
    • Everyone in the nabberhod was in a gang!
    • The gourds whore heavy steel mail and where armed with large pikes.

    Personality

    Finally, we have sentences that give us a peek into the student's psyche.

    • There are many different ballet techniques many of which have not been discovered yet.
    • When I skate I feel accomplished, but to skate and show that I don't care would be the highlight of my life.
    • I thrive on the magnificent history.
    • Money. That word brings joy to me.
    • Fortunately, I'm not crazy.
  • The Old New Thing

    Does Microsoft internally use MFC for writing Windows apps?

    • 38 Comments

    Craig Ward figures that if he asks enough questions I might answer one of them. "Does Microsoft internally use MFC for writing Windows apps? How about VB?"

    People use whatever they decide best meets the requirements for the task at hand. That could be a batch file, a C++ program, a perl script, a web page with a bunch of JScript, use your imagination. Is the number of solutions that use MFC and VB nonzero? I don't know for sure (I'm not in the habit of taking all the programs I see and trying to figure out what language they're written in), but I'd be very surprised if somebody somewhere hasn't thrown together an MFC or VB program to do something, be it a test suite, an install script, a graphical interface over a complicated command-line tool, or something else. It's a big company. I understand that in some parts of the company they even use Macintoshes.

    I'm not going to go into details of specific projects because (3) I am not authorized to talk about it. (I gave reasons one and two two years ago.)

  • The Old New Thing

    How do I print the contents of a rich text control?

    • 5 Comments

    For some reason, people are really puzzled by rich edit printing. I'm no expert on printing, but even I was able to figure it out. The kernel is the EM_FORMATRANGE message. Each time you call it, a little bit more of the rich text control is printed, and the message returns the index of the first unprinted character, which you can pass back in to print the next chunk.

    The rest is just setting up and tearing down.

    BOOL PrintRTF(HWND hwnd, HDC hdc)
    {
     int cxPhysOffset = GetDeviceCaps(hdc, PHYSICALOFFSETX);
     int cyPhysOffset = GetDeviceCaps(hdc, PHYSICALOFFSETY);
     int cxPhys = GetDeviceCaps(hdc, PHYSICALWIDTH);
     int cyPhys = GetDeviceCaps(hdc, PHYSICALHEIGHT);
    
     SendMessage(hwnd, EM_SETTARGETDEVICE, (WPARAM)hdc, cxPhys);
     FORMATRANGE fr;
     fr.hdc = hdc;
     fr.hdcTarget = hdc;
     fr.rc.left = cxPhysOffset;
     fr.rc.right = cxPhysOffset + cxPhys;
     fr.rc.top = cyPhysOffset;
     fr.rc.bottom = cyPhysOffset + cyPhys;
    
     SendMessage(hwnd, EM_SETSEL, 0, (LPARAM)-1);
     SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&fr.chrg);
    
     BOOL fSuccess = TRUE;
     while (fr.chrg.cpMin < fr.chrg.cpMax && fSuccess) {
      fSuccess = StartPage(hdc) > 0;
      if (!fSuccess) break;
      int cpMin = SendMessage(hwnd, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
      if (cpMin <= fr.chrg.cpMin) {
       fSuccess = FALSE;
       break;
      }
      fr.chrg.cpMin = cpMin;
      fSuccess = EndPage(hdc) > 0;
     }
    
     SendMessage(hwnd, EM_FORMATRANGE, FALSE, 0);
    
     return fSuccess;
    }
    

    We start by getting the dimensions of the page and telling the rich edit control what we intend to render to by using the EM_SETTARGETDEVICE message. Next, we need to fill out our FORMATRANGE, which we do by specifying the HDC we are rendering to, as well as the paper dimensions. But what about the character range? We are lazy and let the rich edit control take care of it for us: We select all the text and then ask the rich edit control to tell us what we just selected, which comes back in the form of a CHARRANGE, which is exactly what we needed.

    Next comes the printing loop. While there is still text to print (and we haven't encountered an error), we start a new page, ask the rich edit control to render that page, remember where the next page should begin, and end the current page. There's a little sanity check in there to make sure that the rich edit control made forward progress; if not, then we'll end up in an infinite loop spewing out blank pages! (I have no idea whether this is theoretically possible, but I'm going to protect against it just the same.)

    Once the printing loop is complete, we clean up by sending one last EM_FORMATRANGE message to tell the rich edit control that we're all done and it can discard the information it cached.

    We can take all the information we've learned over the past few days to make a simple "print RTF" program.

    int CALLBACK
    _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
              LPTSTR lpCmdLine, int nShowCmd)
    {
     LoadLibrary(TEXT("riched20.dll"));
     HWND hwndRTF = CreateWindow(RICHEDIT_CLASS, NULL,
                         ES_MULTILINE | WS_OVERLAPPEDWINDOW,
                         CW_USEDEFAULT, CW_USEDEFAULT,
                         CW_USEDEFAULT, CW_USEDEFAULT,
                         NULL, 0, 0, 0);
     if (hwndRTF) {
      SendMessage(hwndRTF, EM_EXLIMITTEXT, 0, -1);
      if (FillRichEditFromFile(hwndRTF, lpCmdLine)) {
       PRINTDLG pd = { sizeof(pd) };
       pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
       if (PrintDlg(&pd)) {
        DOCINFO di = { sizeof(di) };
        di.lpszDocName = TEXT("Sample Printout");
        if (StartDoc(pd.hDC, &di) > 0) {
         if (PrintRTF(hwndRTF, pd.hDC)) {
          EndDoc(pd.hDC);
         } else {
          AbortDoc(pd.hDC);
         }
        }
        GlobalFree(pd.hDevMode);
        GlobalFree(pd.hDevNames);
        DeleteDC(pd.hDC);
       }
      }
      DestroyWindow(hwndRTF);
     }
     return 0;
    }
    

    There's not really much going on here; it's all just glue and necessary typing.

    We create a rich edit control and fill it with the file passed on the command line. We then ask the PrintDlg function to give us a DC to the user's default printer. We give the document a title, start the document, print the rich text into the document, and then end the document (or abort it if something went wrong during printing). A little cleaning up, and we're all done. A tiny program to print an arbitrary RTF document with no fanfare whatsoever.

    See? It's not so hard. Once you find EM_FORMATRANGE the rest is just doing the obvious.

  • The Old New Thing

    The history of the RichEdit control from Murray Sargent

    • 0 Comments

    Murray Sargent is a programmer over in the Office division whose blog deals mostly with math in Office, but he also slips into RichEdit history. If you can't get enough of a history fix from this web site, you can surf on over to Murray's for another hit.

  • The Old New Thing

    How do I put more than 32,000 characters into a rich text control?

    • 10 Comments

    Last time we looked at loading an entire file into a rich text control. The code runs great, until you try to use it to display a license agreement provided by your legal department, and then some paranoid user reports that they can't read past page seven. (What, somebody reads those things?) What's going on?

    If you don't specify otherwise, the maximum number of characters in a rich edit control is 32,767 charaters. (This limit exists for compatibility with the original rich edit control.) You can raise the limit with the EM_EXLIMITTEXT message. Therefore, we need to slip the line

    SendMessage(hwnd, EM_EXLIMITTEXT, 0, -1);
    

    into the program before it calls FillRichEditFromStream.

    Next time, the mystery of rich edit printing.

  • The Old New Thing

    Ken Levine teaches us about television script writing

    • 2 Comments

    Ken Levine has written for some of the most well-known television programs of the past few decades. M*A*S*H, Cheers (for which he won an Emmy), Frasier. And that's not counting his second (third? fourth?) career as a baseball announcer. He writes about whatever is on his mind, be it Barry Bonds' 715th home run, what not to put into your television script, more Cheers trivia than you know what to do with, or Thanksgiving travel tips, and every single one is filled with his personality and attitude. It's a joy to read.

  • The Old New Thing

    How do I load an entire file into a rich text control?

    • 5 Comments

    To load an entire file into a rich text control, you can use the EM_STREAMIN message, which accepts an IStream of data all at once. Once you find the message, it's pretty straightforward how to use it, but I'll write out the code anyway;

    DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE lpBuff,
                                      LONG cb, PLONG pcb)
    {
     HANDLE hFile = (HANDLE)dwCookie;
     return !ReadFile(hFile, lpBuff, cb, (DWORD *)pcb, NULL);
    }
    
    BOOL FillRichEditFromFile(HWND hwnd, LPCTSTR pszFile)
    {
     BOOL fSuccess = FALSE;
     HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ,
                               0, OPEN_EXISTING,
                               FILE_FLAG_SEQUENTIAL_SCAN, NULL);
     if (hFile != INVALID_HANDLE_VALUE) {
      EDITSTREAM es = { (DWORD_PTR)hFile, 0, EditStreamCallback };
      if (SendMessage(hwnd, EM_STREAMIN, SF_RTF, (LPARAM)&es) &&
          es.dwError == 0) {
       fSuccess = TRUE;
      }
      CloseHandle(hFile);
     }
     return fSuccess;
    }
    

    You pretty much follow your nose. The EM_STREAMIN message wants you to tell it the format of the stream (SF_RTF) and provide a pointer to an EDITSTREAM structure that controls the input. Since we want to read from a file, we open a file for reading and use it as the dwCookie for our EditStreamCallback. The only tricky part is getting the return value correct for the callback. For some reason, the rich edit control wants zero on success and nonzero on failure, so we need to flip the sense of the ReadFile return value accordingly. Aside from that, there's nothing particularly interesting going on.

    "But I tried this, and only the first line of the file gets read in. What am I doing wrong?"

    Ah, a classic rookie mistake. You forgot to set the ES_MULTILINE style when you created the rich edit control.

    Don't worry, I made this mistake, too.

    "What if my data is in some other format than a file?"

    As long as you can write a function that produces the next few bytes of data, you can stream it into a rich edit control. For example, here's a version that loads an arbitrary IStream into a rich edit control:

    DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE lpBuff,
                                      LONG cb, PLONG pcb)
    {
     IStream *pstm = (IStream *)dwCookie;
     return FAILED(pstm->Read(lpBuff, cb, (ULONG*)pcb));
    }
    
    BOOL FillRichEditFromStream(HWND hwnd, IStream *pstm)
    {
     BOOL fSuccess = FALSE;
     EDITSTREAM es = { (DWORD_PTR)pstm, 0, EditStreamCallback };
     if (SendMessage(hwnd, EM_STREAMIN, SF_RTF, (LPARAM)&es) &&
         es.dwError == 0) {
      fSuccess = TRUE;
     }
     return fSuccess;
    }
    

    There's still a bug in this code, however, and it's not where you expect it. We'll take another look next time.

  • The Old New Thing

    Article of clothing or tasty dessert?

    • 21 Comments

    Balaclava or baklava?

    I always get the two confused, and I have to stop and think. "Why were the bank robbers covered in a tasty dessert?" "Who wants to eat a hooded knit cap?"

  • The Old New Thing

    What triggers the recall of an offline file?

    • 4 Comments

    Hierarchical storage management is one of the taxes software developers have to pay. What can you safely do to an offline file? What will trigger its recall?

    (First, a note on terminology: Recalling a file means to restore it from remote storage to local storage. A file that has been recalled is online; a file that has been placed on remote storage is offline.)

    Merely opening the file will not recall it. Therefore, you can still open the file and use the handle in functions like GetFileInformationByHandle, GetFileTime, and GetFileSecurity without triggering a recall. But if you read from or write to the file (or map the file, which is the moral equivalent of reading and writing), then the file will be recalled from storage.

    What about the FILE_FLAG_OPEN_NO_RECALL flag? This flag doesn't affect when the remote storage is accessed. (It's still read/write/map.) What it does is tell the hierarchical storage manager to leave the file offline. In other words, if you open an offline file with the FILE_FLAG_OPEN_NO_RECALL flag, then when you read from the file, the file contents will be read from tape directly and the file will remain in its offline state.

    I'm told that the FILE_FLAG_OPEN_NO_RECALL flag is intended for backup programs so that they can back up all your files (even the offline ones) while still keeping them offline.

    (Note: Do not confuse these types of offline files with another feature also confusingly called offline files. This is what happens when you let the Marketing department choose the names of your features.)

  • The Old New Thing

    Why do property sheets sometimes take a first-chance exception?

    • 19 Comments

    Reader cmonachan asked why CPropertySheet::DoModal can cause a first-chance exception. This is mentioned in Knowledge Base article 158552. But why take the exception in the first place?

    First off, let's take MFC out of the picture. The first-chance exception is coming from the property sheet manager. MFC is just the middle-man.

    Okay, so why the first-chance exception? It's not obviously backwards compatibility, since property sheets were new for Windows 95; there was no old property sheet manager to be compatible with.

    But yes, it was for compatibility. Not with an imaginary "earlier version" of the property sheet manager, but with real honest-to-goodness dialog box editing tools.

    Property sheets are nested dialogs. The styles for nested dialogs must include DS_CONTROL and WS_CHILD. What's more, it can't contain styles like DS_ABSALIGN and WS_CAPTION which make no sense for child windows. Most of those styles you can convince your dialog box editing tool to add or remove, but DS_CONTROL is a different story. Since this flag was new for Windows 95, no existing dialog box editing tool supported it.

    Okay, so now you're designing a property sheet manager. What do you do with dialog box templates that have the wrong style?

    Proposal 1: Don't write any special code. Just create the dialog box on the assumption that the caller set the styles correctly.

    The upside of this proposal is that it's the least amount of work. The downside is that if the caller messes up, they just get bizarre behavior (property sheet pages that pop out of the frame, for example) and have no real clue what they did wrong, much less how they can go about fixing it.

    Proposal 2: Write special code to detect incorrect dialog boxes and reject them. Okay, well instead of bizarre behavior, the caller just gets nothing. Still not much help.

    There's a serious problem with the first two proposals: How do you get people to set the styles correctly if their tools aren't capable of doing it? Fire up the dialog box editing tool you've been using and it won't have a check-box for DS_CONTROL because your dialog box editing tool was written for Windows 3.1, and DS_CONTROL didn't exist then.

    You might say, "Well, those people will have to upgrade their dialog box editing tools in order to write programs for Windows 95." The problem with that position is that it creates a chicken-and-egg problem. It's 1994. Windows 95 Beta 1 has just come out. A company wants to "catch the wave" and have a Windows 95 version of their program ready on the day that Windows 95 hits the shelves, so they anxiously install the beta, install the beta SDK, they see this cool new property sheet thing so they sit down to give it a shot and... they're stuck. They can't use property sheets because they need the Windows 95 version of Microsoft Visual C++ or Delphi or Turbo Pascal. But those products don't exist yet because Windows 95 isn't out yet. And it's not just the development tools that would need to be upgraded. It's also the translation tools and all the other tools that manipulate dialog box templates.

    This isn't an imaginary scenario. The Windows 95 team faced this very problem! In order to use these cool property sheet things, they needed to add the DS_CONTROL style to their dialog boxes, but Visual C++ didn't support this style since that style existed only in an operating system that hadn't been released yet.

    Proposal 3: Write special code to detect incorrect dialog boxes and fix them so that people can start writing Windows 95 programs now.

    To fix the dialog box requires modifying the styles, which means modifying the dialog template, and that's where the first-chance exception comes from. When the property sheet manager writes to the dialog template to fix the style, a first-chance exception is raised because resources start out as read-only pages. The kernel catches this exception and write-enables the page, then returns EXCEPTION_CONTINUE_EXECUTION to say, "I fixed the problem, try it again."

    That's where the first-chance exception comes from.

    How do you avoid this first-chance exception? Easy. Get your dialog box styles right in the first place. If you get the styles right, then the property sheet manager won't have to fix them. For the record, here are the style requirements for property sheets:

    Must have Optional
    DS_3DLOOK
    DS_CONTROL
    WS_CHILD
    WS_TABSTOP
    DS_SHELLFONT
    DS_LOCALEDIT
    WS_CLIPCHILDREN

    Any other WS_* and DS_* styles not listed above are forbidden. (Note that I'm talking about styles and not extended styles.)

Page 3 of 4 (35 items) 1234