• The Old New Thing

    Even if you have code to handle a message, you're allowed to call DefWindowProc, because you were doing that anyway after all

    • 16 Comments

    Just because you write case WM_SOMETHING: doesn't mean that you have to handle all possible parameters for the WM_SOMETHING message. You're still allowed to call the DefWindowProc function. After all, that's what you did when you didn't have a case WM_SOMETHING: statement in the first place.

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    default:
        return DefWindowProc(...);
    }
    

    The above code fragment doesn't handle the WM_SOMETHING message at all. Suppose the WM_SOMETHING message uses the wParam parameter to specify what type of something occurred, and you only want to override the default processing in the case where wParam has the value of 4. What do you do with the other values?

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        if (wParam == 4) { DoSomething4(...); }
        else ... ????? ...
        return 0;
    
    default:
        return DefWindowProc(...);
    }
    

    If the value is 4, then you do your special "something 4" processing, but what about all the other values? How do you handle them?

    Well, think about it: How did you handle them before? The original code, before you added a WM_SOMETHING handler, was equivalent to this:

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        return DefWindowProc(...);
    
    default:
        return DefWindowProc(...);
    }
    

    In the original code, since there was no explicit handler for the WM_SOMETHING message, control is transferred to the default case handler, which just calls the DefWindowProc function. If you really want to, you can expand the case out a bit more:

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        if (wParam == 4) return DefWindowProc(...);
        else return DefWindowProc(...);
    
    default:
        return DefWindowProc(...);
    }
    

    Because if the wParam is 4, the original code just called DefWindowProc. And if the wParam was something other than 4, the original code still just called DefWindowProc.

    Of course, I expanded the block in precisely this way so it matches up with the case we started writing when we decided to handle the WM_SOMETHING method. Written out this way, it becomes obvious what to write for the question marks.

    switch (uMsg) {
    case WM_CHAR:
        OnChar(...);
        return 0;
    
    case WM_SOMETHING:
        if (wParam == 4) { DoSomething4(...); }
        else return DefWindowProc(...);
        return 0;
    
    default:
        return DefWindowProc(...);
    }
    

    Just because you have a case WM_SOMETHING statement doesn't mean you have to handle all the cases; you can still call DefWindowProc for the cases you don't want to handle.

    Armed with this information, you can help commenter Norman Diamond handle the VK_F10 key in his WM_SYSKEYDOWN message handler without having to "start handling a bunch of keys that really are system keys, that I didn't want to bother with."

  • The Old New Thing

    Kindergarten writing exercise from my niece

    • 21 Comments

    When my niece was in kindergarten, a regular classroom assignment was for students to write a few sentences about something happening in their lives. For one of the assignments, my niece wrote the following:

    My auntie has a baby in her tumy. If it is a boy I will call him Kevin. If it is a grl I will call her Alula.

    We have no idea where the name "Alula" came from.

    The baby turned out to be a girl, but her aunt chose a different name.

    My niece did not hold up her end of the bargain and call her new cousin "Alula".

    Update: Upon further reflection, I think the proposed boy's name was "Derik", not Kevin. Not important to the story, but included for completeness.

  • The Old New Thing

    If a process crashes while holding a mutex, why is its ownership magically transferred to another process?

    • 29 Comments

    A customer was observing strange mutex ownership behavior. They had two processes that used a mutex to coordinate access to some shared resource. When the first process crashed while owning the mutex, they found that the second process somehow magically gained ownership of that mutex. Specifically, when the first process crashed, the second process could take the mutex, but when it released the mutex, the mutex was still not released. They discovered that in order to release the mutex, the second process had to call Release­Mutex twice. It's as if the claim on the mutex from the crashed process was secretly transferred to the second process.

    My psychic powers told me that that's not what was happening. I guessed that their code went something like this:

    // code in italics is wrong
    bool TryToTakeTheMutex()
    {
     return WaitForSingleObject(TheMutex, TimeOut) == WAIT_OBJECT_0;
    }
    

    The code failed to understand the consequences of WAIT_ABANDONED.

    In the case where the mutex was held by the first process when it crashed, the second process will attempt to claim the mutex, and it will succeed, and the return code from Wait­For­Single­Object will be WAIT_ABANDONED. Their code treated that value as a failure code rather than a modified success code.

    The second program therefore claimed the mutex without realizing it. That is what led the customer to believe that ownership was being magically transferred to the second program. It wasn't magic. The second program misinterpreted the return code.

    The second program saw that Try­To­Take­The­Mutex "failed", and it went off and did something else for a while. Then the next time it called Try­To­Take­The­Mutex, the function succeeded: It was a successful recursive acquisition, but the program thought it was the initial acquisition.

    The customer didn't reply back, so we never found out whether that was the actual problem, but I suspect it was.

  • The Old New Thing

    Puzzling out the upsell-o-meter

    • 21 Comments

    As I noted before, many grocery stores in the United States have a printer next to the cash register which prints out coupons customized to your purchases. Here's a purchase and the accompanying coupon. What is the story behind this pairing?

    Purchased: Diapers for newborn baby.
    Coupon: Save 75 cents on ice cream.

    Bonus chatter: While waiting in line, I read the warning label on the diapers. It went on for quite a bit, but one part triggered my "I wonder what lawsuit led to this warning" sensor: "Like most articles of clothing, XYZ brand diapers will burn if exposed to flame." Did somebody say, "Oh no, there's a fire, what will I do? I know, I'll smother the fire with my baby's diapered bottom!"

  • The Old New Thing

    Long Zheng interviews Hamad Darwish about those Windows Vista wallpapers

    • 2 Comments

    Long Zheng followed up on the story of where the default wallpapers in Windows Vista came from and managed to score an interview with Hamad Darwish, one of those amateur photographers.

  • The Old New Thing

    When should I use the FIND_FIRST_EX_LARGE_FETCH flag to FindFirstFileEx?

    • 14 Comments

    Windows 7 introduces a new flag to the Find­First­File­Ex function called FIND_FIRST_EX_LARGE_FETCH. The documentation says that it "uses a larger buffer for directory queries, which can increase performance of the find operation." This is classic MSDN-style normative documentation: It provides "just the facts". Far be it for MSDN to tell you how to write your application; the job of function-level documentation is to document the function. If you want advice, go see a therapist.

    If the reason why you're calling Find­First­File­Ex is to enumerate through the entire directory and look at every entry, then a large buffer is a good thing because it reduces the number of round trips to the underlying medium. If the underlying medium is a network drive halfway around the world, the latency will be high, and reducing the number of calls reduces the overall cost of communication. Another case where you have high latency is if you are enumerating from an optical drive, since those tend to be slow to cough up data, and once you get the medium spinning, you want to get all the information you can before the drive spins the medium back down. On the other hand, if your underlying medium has low latency, then there isn't much benefit to using a large buffer, and it can be a detriment if the channel is low bandwidth, because transferring that large buffer will take a long time, which can result in long pauses on your UI thread.

    But what if you aren't enumerating with the purpose of reading the entire contents but rather are going to abandon the enumeration once you get the answer to your question? For example, maybe your function wants to enumerate the directory to see if it contains more than ten files. Once the tenth call to Find­Next­File succeeds, you're going to abandon the enumeration. In this case, a large buffer means that the underlying medium is going to do work that you will end up throwing away.

    Here's the above discussion summarized in a table, since people seem to like tables so much.

    Scenario Use FIND_FIRST_EX_LARGE_FETCH?
    Enumerating entire directory on UI thread No¹
    on background thread Yes
    Abandoning enumeration prematurely No

    ¹Actually, if you're on a UI thread, you should try to avoid any directory enumeration at all.

  • The Old New Thing

    How do I suppress the default animation that occurs when I hide or show a window?

    • 18 Comments

    A customer wanted to know how they can disable the default fade-in/fade-out animation that occurs when a window is hidden or shown. "I don't want to use WS_EX_TOOL­WINDOW because that causes my window to disappear from the taskbar. I tried Dwm­Enable­Composition but that affects the entire desktop and is too jarring. We want to suppress the effect because our program replaces one window with another, and we want the operation to be invisible to the user."

    Whoa, heading straight for Dwm­Enable­Composition? That's using a global solution to a local problem.

    To disable the animations on a specific window, use something like this:

    HRESULT DisableDwmAnimations(HWND hwnd)
    {
        BOOL fDisable = TRUE;
        return DwmSetWindowAttribute(hwnd,
                    DWMWA_TRANSITIONS_FORCEDISABLED,
                    &fDisable,
                    sizeof(fDisable));
    }
    

    Re-enabling the animations is left as an exercise for the reader.

  • The Old New Thing

    Luxurifying the camping experience in a different direction

    • 14 Comments

    Some time ago, I noted the increasing luxurification of camping, where people with more money than sense decide to go through the camping experience without building any of the character that comes with it.

    But that's not the only direction luxurification has moved. Unwilling to accept that "getting there is half the fun", some people take chartered planes to and from summer camp. Stick it out for the punch line in the final sentence of the article.

  • The Old New Thing

    The conversations backstage at computer Go tournaments

    • 7 Comments

    Steve Rowe linked to an essay on why computers can't play Go well even though they've mastered other "difficult" games like chess. I was reminded of a description I received of what happens backstage at computer Go tournaments (i.e., tournaments that pit Go-playing computers against each other). ("Backstage" is a bit of a misnomer, of course; since the contestants are computers, you can talk all you want as loud as you want without worrying about distracting the players.)

    At computer Go tournaments, the programmers are like parents watching their children compete in a hockey game where they've only just barely learned how to skate. It's not so much a matter of who plays better as it is a matter of who sucks less. One programmer will lean over to the other and say something like "I hope my program realizes its left-hand-side is vulnerable before your program takes advantage of it."

  • The Old New Thing

    Overheard conversation fragment: Shrimp is not vegetables

    • 33 Comments

    I walked past a woman in the grocery store who was talking on her mobile phone. I only caught one sentence. She said, in an annoyed voice, "Shrimp is not vegetables."

    (Then again, purple is a fruit, so anything's possible.)

    Update: manicmarc correctly deduced that the tone and body language of the person on the phone indicated that her previous sentence in the conversation was something like "What vegetables do you want to have with dinner?"

Page 375 of 447 (4,467 items) «373374375376377»