December, 2010

  • The Old New Thing

    2010 year-end link clearance

    • 30 Comments

    Another round of the semi-annual link clearance.

    And, as always, the obligatory plug for my column in TechNet Magazine:

    • Beware the Balloon.
    • Hiding in Plain Sight.
    • History—the Long Way Through. In their zeal to make this article meet length, the editors cut what I consider to be the most important part of the article! Here's the penultimate paragraph in its full unedited version, with the important part underlined.
      But wait, there's still more. What if you want to access the real 64-bit system directory from a 32-bit process? File system redirection will take your attempt to access the C:\Windows\System32 directory and redirect it to the C:\Windows\SysWOW64 directory. Programmatically, you can use functions with unwieldy names like Wow64­Disable­Wow64­Fs­Redirection, but those disable redirection for all operations until re-enabled, which causes trouble if you're doing anything more complicated than opening a single file, because a complex operation may result in multiple files being accessed and possibly even worker threads being created. Instead of using a gross switch like disabling file system redirection, you can use the special C:\Windows\SysNative virtual directory. When a 32-bit process tries to access the C:\Windows\SysNative directory, the operations are redirected to the real C:\Windows\System32 directory. A local solution to a local problem.
    • Leftovers from Windows 3.0.
    • The Story of Restore.
    • The Tumultuous History of 'Up One Level'. The editors messed up the diagram in this article. The "1" is supposed to be an "open folder" icon, but due to the same error that results in that mysterious J, the Wingdings glyph turned into a plain "1". Here's what the diagram was supposed to look like. (Of course, if your browser is one who believes that Wingdings doesn't have a "1" glyph, then you'll just see a "1".)

      So for those of you looking for your Up One Level button, it's right there on the Address Bar. I've drawn a box around it so it's easier to see.

      Computer OS (C:) Windows Web Wallpaper
  • The Old New Thing

    What makes RealGetWindowClass so much more real than GetClassName?

    • 7 Comments

    There's Get­Class­Name and then there's Real­Get­Window­Class. What makes Real­Get­Window­Class more real?

    Recall from last time that the Real... functions were added to support Windows accessibility. The goal with Real­Get­Window­Class is to help accessibility tools identify what kind of window it is working with, even if the application did a little disguising in the form of superclassing.

    If you ask Real­Get­Window­Class for the class name of a window, it digs through all the superclassing and returns the name of the base class (if the base class is one of the standard window manager classes). For example, if your application superclassed the button class, a call to Get­Class­Name would return Awesome­Button, but a call to Real­Get­Window­Class would return button. Returning the underlying window class allows accessibility tools to know that the user is interacting with some type of button control (albeit a customized one), so that it can adjust the interaction to something appropriate for buttons. Without Real­Get­Window­Class, the accessibility tool would just see Awesome­Button, and it would probably shrug and say, "I have no idea what a Awesome­Button is."

    (I guess you could have the accessibility tool do a strstr for button, but then it would be faked out by classes like Button­Bar or applications which superclass a button but call it something completely different like Awesome­Radio.)

    If you read the winuser.h header file, you can see a comment next to the Real­Get­Window­Class function:

    /*
     * This gets the name of the window TYPE, not class.  This allows us to
     * recognize ThunderButton32 et al.
     */
    

    What is Thunder­Button32?

    Thunder was the code name for Visual Basic 1.0. Visual Basic superclassed all the standard Windows controls and called its superclassed version Thunder­Whatever.

  • The Old New Thing

    WindowFromPoint, ChildWindowFromPoint, RealChildWindowFromPoint, when will it all end?

    • 21 Comments

    Oh wait, there's also ChildWindowFromPointEx.

    There are many ways of identifying the window that appears beneath a point. The documentation for each one describes how they work, but I figured I'd do a little compare/contrast to help you decide which one you want for your particular programming problem.

    The oldest functions are WindowFromPoint and ChildWindowFromPoint. The primary difference between them is that WindowFromPoint returns the deepest window beneath the point, whereas ChildWindowFromPoint returns the shallowest.

    What do I mean by deep and shallow?

    Suppose you have a top-level window P and a child window C. And suppose you ask one of the above functions, "What window is beneath this point?" when the point is squarely over window C. The WindowFromPoint function looks for the most heavily nested window that contains the point, which is window C. On the other hand ChildWindowFromPoint function looks for the least nested window that contains the point, which is window P, assuming you passed GetDesktopWindow as the starting point.

    That's the most important difference between the two functions, but there are others, primarily with how the functions treat hidden, disabled, and transparent windows. Some functions will pay attention to hidden, disabled, and/or transparent windows; others will skip them. Note that when a window is skipped, the entire window hierarchy starting from that window is skipped. For example, if you call a function that skips disabled windows, then all children of disabled windows will also be skipped (even if the children are enabled).

    Here we go in tabular form.

    Function Search Hidden? Disabled? Transparent?¹
    WindowFromPoint Deep Skip Skip It's Complicated²
    ChildWindowFromPoint Shallow Include Include Include
    ChildWindowFromPointEx Shallow Optional Optional Optional
    RealChildWindowFromPoint Shallow Skip Include Include³

    The return values for the various ...FromPoint... functions are the same:

    • Return the handle of the found window, if a window was found.
    • Return the handle of the parent window if the point is inside the parent window but not inside any of the children. (This rule obviously does not apply to WindowFromPoint since there is no parent window passed into the function.)
    • Otherwise, return NULL.

    The entries for ChildWindowFromPointEx are marked Optional because you, the caller, get to specify whether you want them to be skipped or included based on the CWP_* flags that you pass in.

    ¹There is a lot hiding behind the word Transparent because there are multiple ways a window can be determined transparent. The ...ChildWindowFromPoint... functions define transparent as has the WS_EX_TRANSPARENT extended window style.

    ²On the other hand, WindowFromPoint defines transparent as returns HTTRANSPARENT in response to WM_NCHITTEST. Actually, that's still not true. If the window belongs to a process thread different from the one calling WindowFromPoint, then WindowFromPoint will not send the message and will simply treat the window as opaque (i.e., not transparent).

    ³The RealChildWindowFromPoint includes transparent windows in the search, but has a special case for group boxes: The RealChildWindowFromPoint function skips over group boxes, unless the return value would have been the parent window, in which case it returns the group box after all.

    Why is RealChildWindowFromPoint so indecisive?

    The RealChildWindowFromPoint function was added as part of the changes to Windows to support accessibility. The intended audience for RealChildWindowFromPoint is accessibility tools which want to return a "reasonable" window beneath a specific point. Since group boxes usually enclose other controls, RealChildWindowFromPoint prefers to return one of the enclosed controls, but if the point belongs to the group box frame, then it'll return the group box.

    One place I see confusion over the various ...WindowFromPoint... functions is code which uses one of the functions, and then massages the result, unaware that there is already a function that returns the pre-massaged result for you. For example, I've seen code which calls WindowFromPoint followed by GetAncestor(GA_ROOT). This does a pointless down-and-up traversal of the window tree, searching for the deepest window that lies beneath the specified point, then walking back up the tree to convert it to a shallow window. This is the Rube Goldberg way of calling ChildWindowFromPointEx(GetDesktopWindow(), ...).

    Next time, a look at the mysterious RealGetWindowClass function. What makes this function more real?

  • The Old New Thing

    Psychic debugging: When I copy a file to the clipboard and then paste it, I get an old version of the file

    • 30 Comments

    A customer reported the following strange problem:

    I tried to copy some text files from my computer to another computer on the network. After the copy completes, I looked at the network directory and found that while it did contain files with the same names as the ones I copied, they have completely wrong timestamps. Curious, I opened up the files and noticed that they don't even match the files I copied! Instead, they have yesterday's version of the files, not incorporating the changes that I made today. I still have both the source and destination folders open on my screen and can confirm that the files I copied really are the ones that I modified and not files from some backup directory.

    I tried copying it again but still an outdated version of the file gets copied. Curiously, the problem does not occur if I use drag/drop to copy the files. It happens only if I use Ctrl+C and Ctrl+V. Any ideas?

    This was indeed quite puzzling. One possibility was that the customer was mistakenly copying out of a Previous Versions folder. Before we could develop some additional theories, the customer provided additional information.

    I've narrowed down the problem. I've found that this has something to do with a clipboard tool I've installed. Without the tool running, everything is fine. How is it that with the tool running, Explorer is copying files through some sort of time machine? Those old versions of the files no longer exist on my computer; where is Explorer getting them from?

    Other people started investigation additional avenues, taking I/O trace logs, that sort of thing. Curiously, the I/O trace shows that while Explorer opened both the source and destination files and issued plenty of WriteFile calls to the destination, it never issued a ReadFile request against the source. An investigation of Previous Versions shows that there are no previous versions of the file recorded in the file system. It's as if the contents were being created from nothing.

    While the others were off doing their investigations, my head shuddered and I was sent into a trance state. A hollow voice emanated from my throat as my psychic powers manifested themselves. Shortly thereafter, my eyes closed and I snapped back to reality, at which point I frantically typed up the following note while I still remembered what had happened:

    My psychic powers tell me that this clipboard program is "virtualizing" the clipboard contents (replacing whatever is on the clipboard with its own data) and then trying (and failing) to regurgitate the original contents when the Paste operation asks for the file on the clipboard.

    A closer investigation of the clipboard enhancement utility showed that one of its features was the ability to record old clipboard contents and replay them (similar to the Microsoft Office Clipboard). Hidden inside the I/O operations was a query for the last-access time.

    And that's when things fell into place.

    Starting in Windows Vista, last access time is no longer updated by default. The program apparently saw that the file was never accessed and assumed that that meant that it also had never been modified, so it regenerated the file contents from its internal cache. (The quick fix for the program would be to switch to checking the last modified time instead of the last access time.)

    Upon learning that my psychic powers once again were correct, I realized that my prize for being correct was actually a penalty: Now even more people will ask me to help debug their mysterious problems.

  • The Old New Thing

    Windows 7 not only can make a wallpaper slide show from images on your computer, it can even pull them from an RSS feed

    • 29 Comments

    Buried in the theme file documentation is a section called [Slideshow] which lets you control the source for images that are used when you put the desktop wallpaper in slideshow mode. And a bonus feature hidden in the [Slideshow] section is the ability to draw the images from an RSS feed. After creating the .theme file, double-click it and it will be added to the list of available themes.

    One thing about the RSS feed is that when you first set it up, it'll probably take a while for the initial images to download. You don't get any feedback that the images are still downloading; they just show up once they're ready. So don't freak out.

    Well, okay, if the images have already downloaded and you still don't see them, then maybe you can freak out. (Did you remember to select the theme after you added it to the list of available themes?)

  • The Old New Thing

    Why can't you use the space bar to select check box and radio button elements from a menu?

    • 17 Comments

    Nektar wants to know why you can't use the space bar to select check box and radio button elements from a menu.

    The short answer is "Because it's a menu, not a dialog box."

    The check mark and radio button are just visual adornments provided by the menu manager as a courtesy; they do not affect the behavior of the menu itself. Notice, for example, that there is no way to specify "radio button groups" in a menu, so the menu manager wouldn't know which items needed to be deselected when you select a radio button menu item. (I guess it could infer them from separators, but then you would have people saying "I want my radio button group to exclude item number 4, but I don't want to put a separator in between; that looks ugly.")

    And then how would a program reject an auto-selected check box or radio button? E.g., the user pushes the space bar to turn on Show the Widget Bar and an error occurs trying to show the Widget Bar. If the program displays an error dialog, that would dismiss the menu. So maybe the program would just silently re-uncheck the box, which leaves the user puzzled as to why the space bar "doesn't work" for turning on the Widget Bar. Or worse, what if hiding the Widget Bar causes the menu to reconfigure itself? (Maybe there are some menu items that are visible only when the Widget Bar is selected; if the user hides the Widget Bar, those menu items need to be deleted.) Windows doesn't have a precedent for menus reconfiguring themselves while they're being displayed. What if one of the items that gets deleted when you hide the Widget Bar is the menu item that contains the Widget Bar checkbox? ("I turned off the Widget Bar, and my menu disappeared!")

    That said, there is no technical reason these design issues couldn't be overcome. You could have a style like MF_GROUP that behaves like WS_GROUP to establish the scope of menu radio buttons; you could have some way to mark a menu item as "this is an unselected check box" or "this is an unselected radio button"; you could come up with a way for a program to reject a user's attempt to change the check box status; you could design a way for menus to be dynamically reconfigured while they are open; you could even design a way for menus to respond in some vaguely reasonable way when the item the user just selected gets dynamically deleted! But all of these features take effort, and they detract from the simple design of a menu as "Here's a list of things you can do. Pick one. Once you pick one, the menu dismisses." Every feature starts out with minus 100 points and needs to beat out the other 200 items on the list.

  • The Old New Thing

    Some suggestions on improving the assembly instructions for your children's play furniture

    • 19 Comments

    Some suggestions for those companies which produce children's play furniture:

    1. If a part is 99.9% symmetric, please call out the other 0.1%. Otherwise, the person doing the assembling will waste five minutes trying to get it to fit before realizing, "Oh, I have to turn it the other way."
    2. Do not refer to the same part by multiple names. Try to stick to the name as it appears in the parts list. Otherwise, the person doing the assembling will not know which one is the M5 × 30mm screw.
    3. Corollary: If you refer to a part, please make sure it appears in the parts list.
    4. Do not omit steps on the assumption that the person doing the assembling has read ahead. "Step 5: Insert X into Y. Step 6: Close snaps around the sides of Y." Invisible step 4.5: "Open the snaps around the sides of Y so that X will fit."
    5. Take into account that the person doing the assembling is most likely being pestered by at least one excited kid during the assembly process. And is probably tired.
  • The Old New Thing

    That mysterious \001

    • 6 Comments

    Some time ago, we learned the story of that mysterious J. There is another mystery character that sometimes shows up in place of a smiley face: the \001.

    The character starts out as the Unicode U+263A, which looks like this: ☺. In code page 437, this character lives at position 1, and depending on what program is being used to display the character, it might appear as a box (representing the character U+0001) or as the escape sequence \001.

    You can think of this as a version of the mysterious J, but taking a route through code page 437, or you can think of it as how a bullet turns into a beep taken in reverse, then reversed again.

  • The Old New Thing

    What is the correct way of temporarily changing a thread's preferred UI language?

    • 10 Comments

    A customer ran into a crashing bug in their shell extension. The shell extension wants to change the thread's preferred UI language temporarily, so that it can load its resources from a specific language. You'd think this would be easy:

    // error checking elided for simplicity
    // There is a bug in this code - read on
    
    // Get the current thread preferred UI languages
    ULONG cLanguages;
    PZZWSTR pszzPrevLanguages;
    ULONG cchPrevLanguages = 0;
    GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                                  &cLanguages, NULL,
                                  &cchPrevLanguages);
    pszzPrevLanguages = new WCHAR[cchPrevLanguages];
    GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                                  &cLanguages,
                                  pszzPrevLanguages,
                                  &cchPrevLanguages);
    
    ... change the thread preferred UI languages ...
    ... load resources ...
    
    // Restore the original thread preferred UI languages
    SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                                  pszzPrevLanguages,
                                  &cLanguages);
    delete[] pszzPrevLanguages;
    

    Approximately ten seconds after this code runs, Explorer crashes with the exception STATUS_CALLBACK_RETURNED_LANG whose description is "A threadpool worker thread enter a callback, which left with preferred languages set. This is unexpected, indicating that the callback missed clearing them." (Just before Explorer crashes, the message "ThreadPool: callback 77180274(05B67430) returned with preferred languages set" appears on the debugger, which says basically the same thing as the status code.)

    Exercise: Why does it take ten seconds before the crash occurs?

    This crash is puzzling, because it's claiming that the callback didn't reset the thread preferred languages, but you can see us doing it right there in the code when we call Set­Thread­Preferred­UI­Languages! Somebody's on crack, but who?

    A closer reading of the error message indicates that the callback needs to "clear" the thread preferred languages, not merely reset them to their original values, and the documentation for Set­Thread­Preferred­UI­Languages says, "To clear the thread preferred UI languages list, the application can set this parameter to a null string or an empty double null-terminated string." Okay, so now the question is, "How can I tell, when I call Get­Thread­Preferred­UI­Languages, that the list of languages I receive back represents the clear state as opposed to indicating that some other code called Set­Thread­Preferred­UI­Languages before I did?"

    The magic is the flag MUI_THREAD_LANGUAGES. If you pass this flag when you call Get­Thread­Preferred­UI­Languages, it will return a null string if the thread has not customized its preferred UI languages, indicating that the way to restore the thread's preferred UI language state is to clear it rather than setting it. Fortunately, this lines up nicely with the way you're supposed to clear the state, so at the end of the day there is no special case.

    The fix to the above code, then, is to make the following simple change:

    // error checking elided for simplicity
    
    // Get the current thread preferred UI languages
    ULONG cLanguages;
    PZZWSTR pszzPrevLanguages;
    ULONG cchPrevLanguages = 0;
    GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME |
                                  MUI_THREAD_LANGUAGES,
                                  &cLanguages, NULL,
                                  &cchPrevLanguages);
    pszzPrevLanguages = new WCHAR[cchPrevLanguages];
    GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME |
                                  MUI_THREAD_LANGUAGES,
                                  &cLanguages,
                                  pszzPrevLanguages,
                                  &cchPrevLanguages);
    
    ... change the thread preferred UI languages ...
    ... load resources ...
    
    // Restore the original thread preferred UI languages
    SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,
                                  pszzPrevLanguages,
                                  &cLanguages);
    delete[] pszzPrevLanguages;
    

    As you might expect, Michael Kaplan has his own thoughts on the Set­Thread­Preferred­UI­Languages function. In fact, he has several such thoughts.

  • The Old New Thing

    The __fortran calling convention isn't the calling convention used by FORTRAN

    • 36 Comments

    Although the Microsoft C compiler supports a calling convention called __fortran, that's just what the calling convention is called; its relationship with the FORTRAN programming language is only coincidental. The __fortran keyword is now just an old-fashioned synonym for __stdcall.

    Various FORTRAN compilers use different calling conventions; the one I describe here applies to the now-defunct Microsoft Fortran PowerStation.

    Fortran Powerstation pushes parameters on the stack right-to-left, with callee-cleanup. (So far, this matches __fortran aka __stdcall.) Function names are converted to all-uppercase, with an underscore at the beginning and @n appended, where n is the number of bytes of parameters. (This still matches __stdcall aside from the uppercase conversion.)

    As for how the parameters are passed, well, that's where things get weird. FORTRAN natively passes all parameters by reference. This is the source of a famous classic FORTRAN bug known as constants aren't.

          PROGRAM MYSTERY
          CALL MAGIC(1)
          PRINT *, 'According to the computer, 3 + 1 is ', ADDUP(3, 1)
          END
    
          FUNCTION ADDUP(I, J)
          ADDUP = I + J
          END
    
    C     What does this subroutine actually do?
          SUBROUTINE MAGIC(I)
          I = 9
          RETURN
    
          END
    

    (It's been a long time since I've written a FORTRAN program, so I may have gotten some of the details wrong, but any errors shouldn't detract from the fundamental issue.)

    When you run this program, it says

    According to the computer, 3 + 1 is 12
    

    How did that happen? We called a function that adds two numbers together, and instead of getting 4, we get 12?

    The reason is the subroutine MAGIC: We passed it the constant 1, and since all FORTRAN parameters are passed by reference, the assignment I = 9 modifies the constant 1. In C:

    int One = 1;
    int Three = 3;
    int Nine = 9;
    
    void Magic(int *i) { *i = Nine; }
    int AddUp(int *i, int *j) { return *i + *j; }
    
    void main()
    {
     Magic(&One);
     printf("According to the computer, 3 + 1 is %d\n",
            AddUp(&Three, &One));
    }
    

    Since Magic modified the constant One, any further use of the constant 1 ends up using the value 9! (According to the FORTRAN standard, modifying a constant results in undefined behavior.)

    Okay, back to calling conventions. Other significant differences between C and FORTRAN: In FORTRAN, array indices begin at 1, not 0, and arrays are stored in column-major order rather than row-major as in C.

    COMPLEX variables in FORTRAN are stored as two floating point numbers (corresponding to the real and imaginary components).

    Functions which return COMPLEX or CHARACTER*(*) are internally rewritten as subroutines where the location to store the return value is passed as a hidden first parameter. (This is analogous to how C returns large structures.)

    The final commonly-encountered weirdness of FORTRAN is that CHARACTER*n data types (which are used to hold strings) are passed as two parameters: The address of the character buffer, followed by the size of the buffer (n). Note that FORTRAN CHARACTER*n variables are fixed-length; if you assign a string shorter than the buffer, it is padded with spaces. There is no null terminator.

    Anyway, I sort of got carried away with the FORTRAN calling convention. It's definitely more complicated than just sticking __fortran in front of your function. But at least the __fortran keyword takes care of the part that can't be expressed in C. The rest you can manage on your own.

Page 1 of 4 (31 items) 1234