September, 2006

  • The Old New Thing

    Allocating and freeing memory across module boundaries

    • 55 Comments

    I'm sure it's been drilled into your head by now that you have to free memory with the same allocator that allocated it. LocalAlloc matches LocalFree, GlobalAlloc matches GlobalFree, new[] matches delete[]. But this rule goes deeper.

    If you have a function that allocates and returns some data, the caller must know how to free that memory. You have a variety of ways of accomplishing this. One is to state explicitly how the memory should be freed. For example, the FormatMessage documentation explicitly states that you should use the LocalFree function to free the buffer that is allocated if you pass the FORMAT_MESSAGE_ALLOCATE_BUFFER flag. All BSTRs must be freed with SysFreeString. And all memory returned across COM interface boundaries must be allocated and freed with the COM task allocator.

    Note, however, that if you decide that a block of memory should be freed with the C runtime, such as with free, or with the C++ runtime via delete or delete[], you have a new problem: Which runtime?

    If you choose to link with the static runtime library, then your module has its own private copy of the C/C++ runtime. When your module calls new or malloc, the memory can only be freed by your module calling delete or free. If another module calls delete or free, that will use the C/C++ runtime of that other module which is not the same as yours. Indeed, even if you choose to link with the DLL version of the C/C++ runtime library, you still have to agree which version of the C/C++ runtime to use. If your DLL uses MSVCRT20.DLL to allocate memory, then anybody who wants to free that memory must also use MSVCRT20.DLL.

    If you're paying close attention, you might spot a looming problem. Requiring all your clients to use a particular version of the C/C++ runtime might seem reasonable if you control all of the clients and are willing to recompile all of them each time the compiler changes. But in real life, people often don't want to take that risk. "If it ain't broke, don't fix it." Switching to a new compiler risks exposing a subtle bug, say, forgetting to declare a variable as volatile or inadvertently relying on temporaries having a particular lifetime.

    In practice, you may wish to convert only part of your program to a new compiler while leaving old modules alone. (For example, you may want to take advantage of new language features such as templates, which are available only in the new compiler.) But if you do that, then you lose the ability to free memory that was allocated by the old DLL, since that DLL expects you to use MSVCRT20.DLL, whereas the new compiler uses MSVCR71.DLL.

    The solution to this requires planning ahead. One option is to use a fixed external allocator such as LocalAlloc or CoTaskMemAlloc. These are allocators that are universally available and don't depend on which version of the compiler you're using.

    Another option is to wrap your preferred allocator inside exported functions that manage the allocation. This is the mechanism used by the NetApi family of functions. For example, the NetGroupEnum function allocates memory and returns it through the bufptr parameter. When the caller is finished with the memory, it frees it with the NetApiBufferFree function. In this manner, the memory allocation method is isolated from the caller. Internally, the NetApi functions might be using LocalAlloc or HeapAllocate or possibly even new and free. It doesn't matter; as long as NetApiBufferFree frees the memory with the same allocator that NetGroupEnum used to allocate the memory in the first place.

    Although I personally prefer using a fixed external allocator, many people find it more convenient to use the wrapper technique. That way, they can use their favorite allocator throughout their module. Either way works. The point is that when memory leaves your DLL, the code you gave the memory to must know how to free it, even if it's using a different compiler from the one that was used to build your DLL.

  • The Old New Thing

    The lost follow-ups: Products and people that appear to have vanished without a trace

    • 29 Comments

    There'll be the big announcement promising a revolution in the computer industry, lots of press coverage, and then... nothing. What ever happened to these companies and products? Does anybody know?

  • The Old New Thing

    The danger of using boldface for Chinese characters

    • 34 Comments

    Take care not to hard-code boldfacing or italics into your code. Chinese and Japanese characters (and to a somewhat lesser extent, Korean characters) do not suffer many types of boldface well. (The three scripts Chinese, Japanese and Korean are collectively called "CJK" scripts.) Many characters are very intricate, and making the strokes bolder can result in a big blob of ink. Consider the Traditional Chinese character which means "celebrate". Making it boldface results in which, depending on which operating system and fonts you have installed, might come out as an unreadable mess. Similarly, CJK scripts do not often use italics on screen, since they also make the characters harder to read.

    What should you do in your program if you need to emphasize something? You should let the localizers choose how they want the emphasis to be performed by allowing them to specify the font face, size and attributes. That way, the localizers for Western languages can specify boldface, whereas those localizing for Chinese or Japanese can specify a larger font size or different font face instead.

    Different versions of Windows cope with boldface CJK fonts with different degrees of success. Windows 2000, as I recall, used a simplified simulated boldface, which didn't handle CJK fonts very well. Windows XP, I'm told, has an enhanced boldface simulation algorithm for CJK fonts. The result is not perfect, but it is much better than what was available in Windows 2000. Windows Vista finally bridges the gap and provides separate boldface fonts for CJK. These custom boldface fonts have been tuned specifically for this purpose and (I'm told) are quite readable.

  • The Old New Thing

    Raymond's excursions into East Asian pop music, episode 3: Morning Musume (モーニング娘)

    • 26 Comments

    It really all started with Katamari Damacy (塊魂). The music for that game is so darned infectious, and it was my fascination with that music that prompted my colleague to loan me the CDs his wife bought while she traveled through Asia. I already mentioned China Dolls (中國娃娃). Another of the CDs in the collection was 4th Ikimasshoi! (4th いきまっしょい! = 4th Let's Go!), the um fourth album from the J-Pop group Morning Musume (モーニング娘 = Morning Girls). I'm sure somebody will correct my Japanese translation.

    Yes, these are the girls who in the United States are probably known only for having pork chops tied to their foreheads while being stalked by a lizard or being chased by American fighter Bob Sapp or being freaked out by a clip from the movie The Ring or traumatizing one of its members by dressing her up like a seal and making her hang out at the polar bear tank. From what I can gather, they aren't so much a pop music group as a marketing phenomenon, what with their own television show and endorsement contracts. And yes, it's a singing group with thirteen members. Thirteen. When I first glanced at the album cover, I just assumed that it was the same four or five singers dressed up in different costumes, but no, it really is a group with a ridiculous number of members.

    Their music is bubble-gum J-Pop, often catchy, but sometimes just plain awful. (And sometimes really awful or horrifically I-can't-even-watch-it awful.) But I found at least the catchy tunes useful, because they're energetic and kept me going on longer bicycle rides. It probably helped that I didn't understand the words, though I strongly suspect they're singing about love. (I also find that even the catchy songs tend to be ruined by the videos.)

    Setting aside the musical merits, I have to admire the logistics of organizing a performance of such a large group. Compare, for example, this music video for Osaka Koi no Uta (大阪 恋の歌 = Osaka Love Song) with a live performance of same. In the music video, you can just cut from one vocalist to the next, but in the live performance, the singers have to physically trade places. It's so complicated that some dedicated fans have color-coded the lyrics to keep track of who sings what.

    Another of my colleagues more tuned into the contemporary music scene learned of my fascination with Japanese pop music and dedicated himself to finding some good Japanese pop music, just to show me that it's not all bubble-gum. More on that in the next episode.

  • The Old New Thing

    Philosophical discussion on when to mark a method as virtual

    • 30 Comments

    When should you mark a method as virtual? This question has both a technical and a philosophical aspect. The technical aspect is well-understood: You mark a method as virtual if you want calls to the method to be invoked on the run-time type of the invoked object rather than on the compile-time type of the invoking reference.

    But there is a heavy philosophical aspect to this question as well. Some people argue that every method should be virtual so that derived classes can override the behavior of the base class in ways the base class may not have anticipated. This grants you maximum flexibility, avoiding having to redesign the class in the future.

    I happen to believe that the cost of this extensibility is badly underestimated. Once you mark a method as virtual, your life becomes much more complicated. Every virtual method is an extensibility point, which means that you have to assume the worst. You can't hold any locks when calling a virtual method (else you may deadlock with the derived class). You have to be prepared for all sorts of reentrancy because the derived class may have decided to call MessageBox in its implementation. You have to revalidate your state after the virtual method returns because the derived class may have done "crazy" things inside that virtual method including possibly destroying the object itself! (Life gets very interesting when control returns to the base class with an invalid "this" pointer.)

    It takes only a few seconds to type the word "virtual" but you need to know what you just signed yourself up for. I'm not saying that virtual methods are bad; I'm saying that you need to understand what you are doing. You don't say "Gosh, somebody might want to override this, so I'll make it virtual." You have to say, "Gosh, I'm creating an extensibility point here that needs to be designed and tested."

    Of course, if your class is private, then you are the only person who can derive from the class, and therefore you can impose rules on what the derived classes are permitted to do if they override a method, and you have the power to enforce said rules on those derived classes since you're the one who wrote them anyway. But if you allow others to derive from your class, then you have entered the world of extensibility and your life has just gotten a lot more complicated.

  • The Old New Thing

    Grammar review: Verb+particle versus compound noun

    • 32 Comments

    Although the inflections and compound-mania are largely absent from the English language, there are still some vestiges of its Germanic roots. One detail of English grammar that I often see neglected is the distinction between the verb+particle and the compound noun.

    Consider the verb phrase "to shut down", which is the one I see misused most often. This is a verb+particle combination and is treated as two words. When you turn it into a noun, however, it becomes "shutdown", one word. This Knowledge Base article, for example, manages to keep its head on straight for most of the article, using the verb+particle for the verb form and the compound for the noun form:

    \\computername: Use this switch to specify the remote computer to shut down.

    /a: Use this switch to quit a shutdown operation.

    But then it slips up towards the end and uses the compound as a verb:

    To schedule the local computer to shutdown and restart at 10:00 P.M. ...

    In other Germanic languages the distinction is clearer. Consider the Swedish and German verbs for "to make up" (as in, "to make up an alibi"):

    hitta på   påhittad
    legen zurecht   zurechtlegen

    In the verb+particle form, the particle comes after the verb, whereas in the single-word form, the particle comes before the verb. It's therefore more obvious when you have one word and when you have two. English does this only rarely, typically for verbs that retain poetic or archaic appeal ("cast down" → "downcast") and therefore reach back to the language's German roots for their power.

    This is one of the reasons why I'm so fascinated by the Germanic languages: The more I learn about the other languages, the more I learn about my own.

  • The Old New Thing

    If you ask a Yes/No question, make sure the user also knows what happens when they say No

    • 63 Comments

    I was talking with someone last year who had a gripe about a music organizer program. Suppose you create some playlists and then decide, "Oh, nevermind, I don't like this playlist." You highlight the playlist and click "Delete". You then get a dialog box that asks, "Do you want to move the songs in this playlist to the Recycle Bin?"

    "Well, no, I don't want you to recycle those songs. I want to keep the songs. Just delete the playlist," you say to yourself and you click "No".

    Unfortunately, the program was asking you, "Do you want to move the songs to the Recycle Bin or delete the songs permanently from your computer?" The program had already decided that you wanted to delete the songs themselves when you deleted the playlist. It just wanted to know whether you wanted them gone immediately or just tossed into the Recycle Bin. Fortunately, my friend had backups of the songs that had mistakenly been purged from the computer, but it was still quite shocking to see all the music just plain disappear when there was no expectation that anything of the sort was going to happen.

    When programs put up Yes/No dialogs, they usually don't have a problem explaining what will happen when you click Yes. But they also have to make sure users understand what will happen when they click No.

    Window Vista's new Task Dialog makes it easier for programs to make it clearer to users what will happen as the result of pushing a button on a dialog box. Instead of being limited to just "Yes" and "No", you can put more meaningful text on the buttons such as "Save" and "Don't Save", or you could use command buttons and provide an explanatory sentence for each option. Now, programs could always have built custom dialogs with these more descriptive buttons, but doing so meant designing a dialog box from scratch, positioning the buttons precisely according to dialog box layout guidelines, and then writing a custom dialog procedure to handle this new custom dialog. Most people just take the easy way out and use MessageBox. In Windows Vista there is now a way to build slightly more complex dialogs without having to design a dialog template.

    Be careful, however, not to fall into the same trap with task dialogs. The original dialog might have been converted to a task dialog with the buttons "Recycle" and "Don't Recycle", which would not have solved the problem at all.

  • The Old New Thing

    Turns out you can't learn Mandarin Chinese by watching television

    • 16 Comments

    It is generally accepted that language exposure in the first year of a baby's life is important. To what certainly must be the dismay of couch potatoes everywhere, researchers at the University of Washington determined that it's particularly important that it come from a live human being. Watching DVDs doesn't have any effect. What was particularly notable to the researchers was that even just five hours of exposure made a significant impact.

  • The Old New Thing

    Const pointers: Logical consequences

    • 19 Comments

    Consider this follow-up question to the question from last time:

    When I call the PropertySheet function, can I assume that the phpage field of the PROPSHEETHEADER structure will not be modified?

    If we take a look at the declaration of the PropertySheet function, we see that it reads like this:

    typedef const PROPSHEETHEADERA *LPCPROPSHEETHEADERA;
    typedef const PROPSHEETHEADERW *LPCPROPSHEETHEADERW;
    
    WINCOMMCTRLAPI INT_PTR WINAPI PropertySheetA(LPCPROPSHEETHEADERA);
    WINCOMMCTRLAPI INT_PTR WINAPI PropertySheetW(LPCPROPSHEETHEADERW);
    

    Go past all the function declaration specification goo and look at the parameter list. It's a const pointer to a PROPSHEETHEADER structure (either ANSI or Unicode, depending on which flavor of the PropertySheet function you're calling).

    One of the rules for const pointers is that you can read from them but you cannot write to them. Consequently, the PropertySheet function is not allowed to modify the PROPSHEETHEADER structure. Assuming your code doesn't modify the PROPSHEETHEADER yourself, any value on exit from the function will be the same as the value it had on entry.

  • The Old New Thing

    What you don't apologize for is as important as what you do

    • 25 Comments

    In the aftermath of the Zidane head-butt incident, there was a lot of speculation over what Materazzi might have said to provoke Zidane's response.

    Zidane has said he attacked Materazzi because he insulted his mother and sister. Materazzi denied disparaging Zidane's mother.

    I immediately noticed the very precise denial from Materazzi. (I suspect any parent would recognize the same thing.) And my suspicion was vindicated earlier this week:

    Italy's Marco Materazzi said he insulted Zinedine Zidane's sister.
Page 3 of 4 (37 items) 1234