• The Old New Thing

    Why do I have to add 1 to the color index when I set it as the hbrBackground of a window class?

    • 23 Comments

    Our scratch program sets the background color to COLOR_WINDOW by setting the class background brush as follows:

        wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    

    What's with the +1?

    Okay, first of all, let's backtrack a bit.

    The real first question is, "What's the deal with taking an integer (COLOR_WINDOW) and casting it to a HBRUSH and expecting anything sane to happen?"

    The window manager wants to provide multiple ways of setting the class background brush.

    1. The application can request that no automatic background drawing should occur at all.
    2. The application can request custom background drawing and provide that custom drawing by handling the WM_ERASE­BKGND message.
    3. The application can request that the background be a specific brush provided by the application.
    4. The application can request that the background be a specific system color.

    The first three cases are easy: If you don't want automatic background drawing, then pass the hollow brush. If you want custom background drawing, then pass NULL as the brush. And if you want background drawing with a specific brush, then pass that brush. It's the last case that is weird.

    Now, if Register­Class were being invented today, we would satisfy the last requirement by saying, "If you want the background to be a system color, then use a system color brush like this:

        wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
    
    System color brushes match the corresponding system color, so this sets your background to whatever the current system window color is."

    But just as NASA couldn't use the Space Shuttle to rescue the Apollo 13 astronauts, the Register­Class function couldn't use Get­Sys­Color­Brush for class brushes: At the time Register­Class was designed, system color brushes had not yet been invented yet. In fact, they won't have been invented for over a decade.

    Therefore, Register­Class had to find some way of smuggling an integer inside a pointer, and the traditional way of doing this is to say that certain numerically-small pointer values are actually integers in disguise. We've seen this with the HINSTANCE returned by Shell­Execute, with the MAKE­INT­ATOM macro, with the MAKE­INT­RESOURCE/IS_INT­RESOURCE macro pair, and with the second parameter to the Get­Proc­Address function. (There are plenty of other examples.)

    The naïve solution would therefore be to say, "Well, if you want a system color to be used as the brush color, then just cast the COLOR_XXX value to an HBRUSH, and the Register­Class function will recognize it as a smuggled integer and treat it as a color code rather than an actual brush."

    And then you run into a problem: The numeric value of COLOR_SCROLL­BAR is zero. Casting this to a HBRUSH would result in a NULL pointer, but a NULL brush already means something else: Don't draw any background at all.

    To avoid this conflict, the Register­Class function artificially adds 1 to the system color number so that none of its smuggled integers will be mistaken for NULL.

  • The Old New Thing

    What order does the DIR command arrange files if no sort order is specified?

    • 28 Comments

    If you don't specify a sort order, then the DIR command lists the files in the order that the files are returned by the Find­First­File function.

    Um, okay, but that just pushes the question to the next level: What order does Find­First­File return files?

    The order in which Find­First­File returns files in unspecified. It is left to the file system driver to return the files in whatever order it finds most convenient.

    Now we're digging into implementation details.

    For example, the classic FAT file system simply returns the names in the order they appear on disk, and when a file is created, it is merely assigned the first available slot in the directory. Slots become available when files are deleted, and if no slots are available, then a new slot is created at the end.

    Modern FAT (is that an oxymoron?) with long file names is more complicated because it needs to find a sequence of contiguous entries large enough to hold the name of the file.

    There used to be (maybe there still are) some low-level disk management utilities that would go in and manually reorder your directory entries.

    The NTFS file system internally maintains directory entries in a B-tree structure, which means that the most convenient way of enumerating the directory contents is in B-tree order, which if you cover one eye and promise not to focus too closely looks approximately alphabetical for US-English. (It's not very alphabetical for most other languages, and it falls apart once you add characters with diacritics or anything outside of the Latin alphabet, and that includes spaces and digits!)

    The ISO 9660 file system (used by CD-ROMs) requires that directory entries be lexicographical sorted by ASCII code point. Pretty much everybody has abandoned the base ISO 9660 file system and uses one of its many extensions, such as Joliet or UDF, so you have that additional wrinkle to deal with.

    If you are talking to a network file system, then the file system on the other end of the network cable could be anything at all, so who knows what its rules are (if it even has rules).

    When people ask this question, it's usually in the context of a media-playing device which plays media from a CD-ROM or USB thumb drive in the raw native file order. But they don't ask this question right out; they ask some side question that they think will solve their problem, but they don't come out and say what their problem is.

    So let's solve the problem in context: If the storage medium is a CD-ROM or an NTFS-formatted USB thumb drive, then the files will be enumerated in sort-of-alphabetical order, so you can give your files names like 000 First track.mp3, 001 Next track.mp3, and so on.

    If the storage medium is a FAT-formatted USB thumb drive, then the files will be enumerated in a complex order based on the order in which files are created and deleted and the lengths of their names. But the easy way out is simply to remove all the files from a directory then move file files into the directory in the order you want them enumerated. That way, the first available slot is the one at the end of the directory, so the file entry gets appended.

    Of course, none of this behavior is contractual. NTFS would be completely within its rights to, for example, return entries in reverse alphabetical order on odd-numbered days. Therefore, you shouldn't write a program that relies on any particular order of enumeration. (Or even that the order of enumeration is consistent between two runs!)

  • The Old New Thing

    What two-year-olds think about when they are placed in time-out

    • 10 Comments

    My niece (two years old at the time) was put in the corner as punishment for some sort of misdeed. At the expiration of her punishment, her grandfather returned and asked her, "你乖唔乖?" (Are you going to be nice?)

    She cheerfully replied, "仲未乖!" (Still naughty!)

    In an unrelated incident, one of my honorary nieces was being similarly punished. She told her aunt who was passing nearby, "In a little while, my daddy is going to ask me if I'm sorry. I'm not really sorry, but I'm going to say that I am."

  • The Old New Thing

    Adventures in automation: Dismissing all message boxes from a particular application but only if they say that the operation succeeded

    • 13 Comments

    Suppose you have a program that is part of your workflow, and it has the annoying habit of showing a message box when it is finished. You want to automate this workflow, and part of that automation is dismissing the message box.

    Let's start by writing the annoying program:

    #include <windows.h>
    
    int WINAPI WinMain(
        HINSTANCE hinst, HINSTANCE hinstPrev,
        LPSTR lpCmdLine, int nCmdShow)
    {
      Sleep(5000);
      MessageBox(nullptr, GetTickCount() % 1000 < 800 ?
                 "Succeeded!" : "Failed!", "Annoying", MB_OK);
      return 0;
    }
    

    This annoying program pretends to do work for a little while, and then displays a message box saying whether or not it succeeded. (Let's say it succeeds 80% of the time.)

    Our Little Program will automate this task and respond based on whether the operation succeeded. This is just a small extension of our previous program which logs the contents of every message box, except we are paying attention only to one specific message box.

    To the rescue: UI Automation.

    using System.Windows.Automation;
    using System.Diagnostics;
    using System.Threading;
    
    class Program
    {
     [System.STAThread]
     public static void Main(string[] args)
     {
      int processId = 0;
      bool succeeded = false;
      var resultReady = new ManualResetEvent(false);
    
      Automation.AddAutomationEventHandler(
       WindowPattern.WindowOpenedEvent,
       AutomationElement.RootElement,
       TreeScope.Children,
       (sender, e) =>
       {
        var element = sender as AutomationElement;
    
        if ((int)element.GetCurrentPropertyValue(
                 AutomationElement.ProcessIdProperty) != processId)
        {
         return;
        }
    
        var text = element.FindFirst(TreeScope.Children,
          new PropertyCondition(AutomationElement.AutomationIdProperty,
                                "65535"));
        if (text != null && text.Current.Name == "Succeeded!")
        {
         succeeded = true;
         var okButton = element.FindFirst(TreeScope.Children,
           new PropertyCondition(AutomationElement.AutomationIdProperty,
                                 "2"));
         var invokePattern = okButton.GetCurrentPattern(
           InvokePattern.Pattern) as InvokePattern;
         invokePattern.Invoke();
        }
    
        resultReady.Set();
       });
    
      // Start the annoying process
      Process p = Process.Start("annoying.exe");
      processId = p.Id;
    
      // Wait for the result
      resultReady.WaitOne();
    
      if (succeeded)
      {
       Process.Start("calc.exe");
      }
    
      Automation.RemoveAllEventHandlers();
     }
    }
    

    Most of this program you've seen before.

    We register an automation event handler for new window creation that ignores windows that belong to processes we don't care about. That keeps us from being faked out by windows that happen to be created while our annoying task is running.

    For simplicity's sake, I've removed other sanity checks which verify that the window which appeared is the one we actually care about. In real life, we might check the window class or the window title. I left that out because it's not really relevant to the story.

    Once we think we have the window we want, we suck out the text so we can see whether the message was a success or failure message. If it was a success, we dismiss the dialog box by pushing the OK button; otherwise we leave the error message on the screen so the user can see what happened. Either way, we signal the main thread that we have a result.

    After registering the event handler, we run the annoying process, tell the event handler the process ID, and wait for the signal. Once the signal arrives, we see whether it declared the operation a success, and if so, we proceed to the next step of, um, say, launching the calculator. (I just picked something arbitrary.)

  • The Old New Thing

    How can I detect that my program was run from Task Scheduler, or my custom shortcut, or a service, or whatever

    • 53 Comments

    Suppose you want your program to behave differently depending on whether it is launched from the Start menu, or by clicking the pinned icon on the taskbar, or by Scheduled Task, or from a service, or whatever. How can a program detect and distinguish these scenarios?

    The answer is you don't. And you shouldn't try.

    Instead of trying to guess how your program was executed, you should have the launcher tell you how they are executing your program. You do this by registering a different command line for each of the scenarios, and then checking for that command line in the program. (We saw a variation of this a little while ago.)

    For example, you could have your Start menu shortcut contain one command line parameter, give the taskbar pinned shortcut a different command line parameter, register yet another command line parameter with the task scheduler, and have the service launch the program with a still different command line parameter.

    They all run the same program, but the command line parameter lets the program know what context it is being run in and alter its behavior accordingly.

    It's like creating multiple email addresses that all map to the same inbox. Many email services let you take an email address and insert a plus sign followed by anything else you like before the at-sign, and it'll all get delivered to the same inbox. The thing after the plus-sign is ignored for delivery purposes, but you can use it to help organize your inbox, so you know that the message sent to bob+expos@contoso.com is related to your fantasy baseball team, whereas bob+ff@contoso.com is something about your frequent flier account.

    One thing you shouldn't do is try to guess, however. Programs that magically change their behavior based on details of the environment lead to problems that are very difficult to debug.

    Given this discussion, perhaps you can provide guidance to this customer:

    How can my DLL detect that it is running inside a service?
  • The Old New Thing

    What does the SEE_MASK_UNICODE flag in ShellExecuteEx actually do?

    • 15 Comments

    Somebody with a rude name wonders what the SEE_MASK_UNICODE flag does.

    It does nothing.

    The flag was introduced when porting the Windows 95 shell to Windows NT. It happened further back in history than I have permission to access the Windows source code history database, but I can guess how it got introduced.

    One of the things that the porting team had to do was make Unicode versions of all the ANSI functions that Windows 95 created. Sometimes this was done by creating separate A and W versions of a function. Sometimes this was done by having separate A and W versions of an interface. Sometimes by adding additional fields to the A version of a structure with a flag that says whether the ANSI or Unicode members should be used.

    My guess is that the porting team initially decided to make Shell­Execute­Ex use that third model, where the SHELL­EXECUTE­INFO structure had a SHELL­EXECUTE­INFO­EX extension with Unicode strings, and the mask specified whether the caller preferred you to use the ANSI strings or the Unicode strings.

    Presumably they decided to change course and switch to having separate SHELL­EXECUTE­INFOA and SHELL­EXECUTE­INFOW structures. But when they switched from one model to the other, they left that flag behind, probably with the intention of removing it once all existing callers had been updated to stop passing the flag, but they never managed to get around to it.

    So the flag is just sitting in the header file even though nobody pays any attention to it.

  • The Old New Thing

    Why are leading digits converted to language-specific digit shapes, but not trailing digits, and how do I suppress the conversion entirely?

    • 18 Comments

    If you have a string like 12345ABCDE67890, and you render it on an Arabic system, you might get ٠١٢٣٤ABCDE67890. The leading digits are rendered as Arabic-Indic digits, but the trailing digits are rendered as European digits. What's going on here?

    This is a feature known as contextual digit substitution. You can specify whether European digits are replaced with native equivalents by going to the Region control panel (formerly known as Regional and Language Options), clicking on the Formats tab, going to Additional settings (formerly known as Customize this format), and looking at the options under Use native digits. The three options there correspond to the three values for LOCAL_IDIGITSUBSTITUTION.

    Programmatically, you can override the user preference (if you know that you are in a special case, like an IP address) by following the instructions in MSDN.

    • Uniscribe: Script­Apply­Digit­Substitution
    • DWrite: IDWrite­Text­Analysis­Sink::Set­Number­Substitution
    • GDI: ETO_NUMERICS­LATIN or ETO_NUMERICS­LOCAL.

    As a last resort, you can stick a Unicode NODS (U+206F) at the beginning of the string to force European digits, or a Unicode NADS (U+206E) to force national digits.

    Bonus chatter: What's the point of contextual digit substitution anyway?

    Suppose you have the string "there are 3 items remaining." (Let's say that all text in lowercase is in Arabic.) You want this 3 to be rendered in Arabic-Indic digits because it is part of an Arabic sentence. On the other hand, if you have the string "that's a really nice BMW 350." you want the 350 to be in European digits since it is part of the brand name "BMW 350".

    Contextual digit substitution chooses whether to use Arabic-Indic digits or European digits by matching them to the characters that immediately precede them. (And if no character precedes them, then it uses the ambient language.)

  • The Old New Thing

    A simple email introduction: Fan mail

    • 6 Comments

    One of my former colleagues on the Windows kernel team wasn't afraid to make changes all across the system when necessary. If the engineering team decided to upgrade to a new version of the C++ compiler, my colleague was the one who gave it a test-drive on the entire Windows source code, and fixed all the warnings and errors that kick up as well as ensuring that it passed the build verification tests before updating the compiler in the official toolset. Beyond that, my colleague also ran around being a superhero, writing tools that needed to be written, fixing tools that were broken, and generally being somebody.

    Since the effect on the Windows project was so far-reaching, everybody on the team knew this person, or at least recognized the name, and as a result, my colleage ended up receiving a lot of email about all different parts of Windows, be they bug reports, requests for help using a particular component, whatever.

    And when the question was about something outside my colleague's sphere of responsibility, the message was forwarded to the correct people with a simple introduction:

    From: A
    To: XYZ-owners, Y
    Subject: Problem with XYZ

    Fan mail.

    From: Y
    To: A
    Subject: Problem with XYZ

    Blah blah blah blah

    I've used this technique a few times, but it's been a while. I should start using it again.

    Bonus chatter: At least one of you has come out and said that you post your complaints here with the expectation that the complaints will be forwarded to the appropriate team. This expectation is false. No such forwarding occurs. This Web site is not a complaint desk.

  • The Old New Thing

    Nieces sometimes extrapolate from insufficient contextual data

    • 10 Comments

    My brother-in-law enjoys greeting his nieces when they come over to visit by throwing them into the air and asking, "叫聲我?" (Who am I?)

    The nieces happily reply, "舅舅." (Uncle.)

    He then tosses them up into the air a second time and says, "大聲啲!" (Louder!)

    And the nieces happily shout, "舅舅!"

    One time, my wife was talking with her brother at a normal volume, and his niece came into the room and said to my wife, "大聲啲! 舅舅聽唔到!" (Louder! Uncle can't hear you!)

    Update: Per Frank's suggestion below, changed the niece's outburst from "舅舅冇聽到!" The incident occurred many years ago, and I cannot remember exactly what was said, so I'll go with what's funnier.

  • The Old New Thing

    Logging the contents of every message box dialog via automation

    • 9 Comments

    Today's Little Program logs the contents of every message box dialog, or anything that vaguely resembles a message box dialog. (Since there's no way for sure to know whether a dialog box is a message box or not.)

    using System.Windows.Automation;
    
    class Program
    {
     [System.STAThread]
     public static void Main(string[] args)
     {
      Automation.AddAutomationEventHandler(
       WindowPattern.WindowOpenedEvent,
       AutomationElement.RootElement,
       TreeScope.Descendants,
       (sender, e) => {
        var element = sender as AutomationElement;
        if (element.GetCurrentPropertyValue(
         AutomationElement.ClassNameProperty) as string != "#32770") {
         return;
        }
    
        var text = element.FindFirst(TreeScope.Children,
         new PropertyCondition(AutomationElement.AutomationIdProperty, "65535"));
        if (text != null) {
         System.Console.WriteLine(text.Current.Name);
        }
       });
      System.Console.ReadLine();
      Automation.RemoveAllEventHandlers();
     }
    }
    

    This is the same pattern as the program we wrote last week, but with different guts when the window opens.

    This time, we see if the class name is #32770, which UI Spy tells us is the class name for dialog boxes. (That this is the numerical value of WC_DIALOG is no coincidence.)

    If we have a dialog, then we look for a child element whose automation ID is 65535, which UI Spy tells us is the automation ID for the text inside a message box dialog. (That the traditional control ID for static controls is -1 and 65535 is the the numerical value of (WORD)-1, is no coincidence.)

    If so, then we print the text.

    If we were cleverer, we could also confirm that the only buttons are OK, Cancel, and so on. Otherwise, we can get faked out by other dialog boxes that contain static text.

Page 5 of 419 (4,184 items) «34567»