• The Old New Thing

    Scripting an Internet Explorer window

    • 10 Comments

    Today's Little Program takes a random walk through MSDN by starting at the Create­Process page and randomly clicking links. The exercise is not as important as the technique it demonstrates.

    function randomwalk(ie, steps) {
     for (var count = 0; count < steps; count++) {
    
      WScript.StdOut.WriteLine(ie.document.title);
    
      var links = ie.document.querySelectorAll("#mainSection a");
      do {
       var randomLink = links[Math.floor(Math.random() * links.length)];
      } while (randomLink.protocol != "http:");
    
      WScript.StdOut.WriteLine("Clicking on " + randomLink.innerText);
      randomLink.click();
    
      while (ie.busy) WScript.Sleep(100);
     }
    }
    

    (I'm assuming the reader can figure out what language this script is written in. If you have to ask, then you probably won't understand this article at all. I am also not concerned with random number bias because Little Program.)

    To talk a random walk through MSDN, we ask for all the links in the main­Section element. Note that I'm taking an undocumented dependency on the structure of MSDN pages. This structure has changed in the past, so be aware that the script may stop working at any time if the MSDN folks choose to reorganize their pages. I'm not too worried since this is a demonstration, not production code. In real life, you are probably going to script a Web page that your team designed (as part of automated testing), so taking a dependency on the DOM is something the QA team can negotiate with the development team. (If your real life scenario really is walking through the MSDN content, then you should use the MSDN content API. Here's sample code.)

    Anyway, we grab a link at random, but throw away anything that is not an http: link. This avoids us accidentally navigating into a mailto: link, for example.

    We then invoke the click() method on the link to simulate the user clicking on it. We could also have just navigated to randomLink.href, but I'm using the click() method because it is more general. Your script may want to tick some checkboxes and then click the Submit button, and those actions can't be performed by navigation.

    We then wait for the Web page to settle down. I'm lazy and am simply using a polling loop. If you want to be clever, you could listen on the on­ready­state­change event, but this is just a Little Program, so I'm content to just poll.

    Once we have settled on the new page, we loop back and do it again.

    Now we just need to drive this helper function.

    var ie = new ActiveXObject("InternetExplorer.Application");
    ie.visible = true;
    ie.navigate("http://msdn.microsoft.com/ms682425");
    
    // Wait for it to load
    while (ie.busy) WScript.Sleep(100);
    
    randomwalk(ie, 10);
    
    ie.Quit();
    

    We create our own instance of Internet Explorer so we can change its carpet without getting anybody upset, navigate it to the Create­Process page, and wait for the page to load. We then use our random­walk function to click on ten successive links, and then when we're done, we bring in the demolition crew to destroy the browser we created.

    For extra evil, you could commandeer an existing Internet Explorer window rather than creating your own. (Now you're barging into somebody's house and rearranging the furniture.)

    var shellWindows = new ActiveXObject("Shell.Application").Windows();
    for (var i = 0; i < shellWindows.Count; i++) {
     var w = shellWindows.Item(i);
     if (w.name == "Windows Internet Explorer") {
      randomwalk(w, 10);
      break;
     }
    }
    

    Making the appropriate changes to random­walk so as not to be MSDN-specific is left as an exercise.

  • The Old New Thing

    When are global objects constructed and destructed by Visual C++?

    • 19 Comments

    Today we're going to fill in the following chart:

    When does it run? Constructor Destructor
    Global object in EXE
    Global object in DLL

    The C++ language specification provides some leeway to implementations on when global static objects are constructed. It can construct the object before main begins, or it construct the object on demand according to complicated rules. You can read [basic.start.init] for the gory details.

    Let's assume for the sake of discussion that global static objects are constructed before main begins.

    For global objects in the EXE, constructing them is no big deal because the C runtime startup code linked into the EXE does a bunch of preparation before calling the formal entry point, be it main or wWin­Main or whatever. And part of that preparation is calling constructors for global objects. Since the C runtime startup code is in charge, it can construct the objects right there.

    When does it run? Constructor Destructor
    Global object in EXE C runtime startup code
    Global object in DLL

    DLLs are similar: The formal Dll­Main entry point is not the actual entry point to the DLL. Instead, the entry point is a function provided by the C runtime, and that function does work before and after calling the Dll­Main function provided by the application. We saw this earlier when we discussed what happens if you return FALSE from DLL_PROCESS_ATTACH.

    Part of this extra work done by the C runtime library is to construct DLL globals in DLL_PROCESS_ATTACH and to destruct them in DLL_PROCESS_DETACH. In other words, the code conceptually goes like this:

    BOOL CALLBACK RealDllMain(
        HINSTANCE hinst, DWORD dwReason, void *pvReserved)
    {
      ...
      case DLL_PROCESS_ATTACH:
       Initialize_C_Runtime_Library();
       Construct_DLL_Global_Objects();
       DllMain(hinst, dwReason, pvReserved);
       ...
    
     case DLL_PROCESS_DETACH:
       DllMain(hinst, dwReason, pvReserved);
       Destruct_DLL_Global_Objects();
       Uninitialize_C_Runtime_Library();
       break;
     ...
    }
    

    Of course, the actual code is more complicated than this, but that's the basic idea. We can fill in two more cells in our table.

    When does it run? Constructor Destructor
    Global object in EXE C runtime startup code
    Global object in DLL C runtime DLL_PROCESS_ATTACH prior to Dll­Main C runtime DLL_PROCESS_DETACH after Dll­Main returns

    The last entry in our table is the tricky one: Who triggers the destruction of global objects in the EXE destructed? The C runtime startup code in the EXE is guaranteed to run at process startup, but how does the C runtime cleanup code run?

    The answer is that the C runtime library hires a lackey. The hired lackey is the C runtime library DLL (for example, MSVCR80.DLL). The C runtime startup code in the EXE registers all the destructors with the C runtime library DLL, and when the C runtime library DLL gets its DLL_PROCESS_DETACH, it calls all the destructors requested by the EXE.

    That's the final cell in our table.

    When does it run? Constructor Destructor
    Global object in EXE C runtime startup code C runtime DLL hired lackey
    Global object in DLL C runtime DLL_PROCESS_ATTACH prior to Dll­Main C runtime DLL_PROCESS_DETACH after Dll­Main returns

    You can now answer this customer question and explain the observed behavior:

    Is it okay to call Load­Library from within constructors of global C++ objects inside a DLL? Currently we am seeing weird behavior when doing so.

    The customer went on to describe what they were observing. Their DLL has global C++ objects which do the following operations in their constructor:

    • Check a setting.
    • If the setting is enabled, call Load­Library to load a helper DLL, then call a function in the helper DLL, The result of that function call alters the global behavior of the original DLL.
    • The function in the helper DLL creates a thread then waits for the thread to produce a result.
    • The helper thread never gets started.

    Result: Process hangs.

  • The Old New Thing

    If only DLLs can get DllMain notifications, how can an EXE receive a notification when a thread is created (for example)?

    • 18 Comments

    When a DLL is loaded, it receives a DLL_PROCESS_ATTACH notification, and when it is unloaded (or when the process terminates), it gets a DLL_PROCESS_DETACH notification. DLLs also receive DLL_THREAD_ATTACH notifications when a thread is created and DLL_THREAD_DETACH notifications when a thread exits. But what if you are an EXE? EXEs don't have a Dll­Main, so there is no way to receive these notifications.

    The trick here is to hire a lackey.

    Create a helper DLL, called, say, LACKEY.DLL. Your EXE links to the lackey, and the lackey's job is to forward all Dll­Main notifications back to your EXE. The DLL would naturally have to have a way for your EXE to provide the callback address, so you might have a function Register­Lackey­Callback.

    typedef BOOL (CALLBACK *LACKEYNOTIFICATION)(DWORD dwReason);
    
    LACKEYNOTIFICATION g_lackeyNotification;
    
    void RegisterLackeyCallback(LACKEYNOTIFICATION lackeyNotification)
    {
     g_lackeyNotification = lackeyNotification;
    }
    
    BOOL WINAPI DllMain(
        HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
    {
     if (g_lackeyNotification) g_lackeyNotification(dwReason);
     return TRUE;
    }
    

    Of course, it is rather extravagant to hire a lackey just for this one task, so you will probably just add lackey responsibilities to some other DLL you've written.

    I don't know if there's a name for this design pattern, so I'm just going to call it the hired lackey pattern.

  • The Old New Thing

    The GetCurrentThread function is like a check payable to Bearer: What it means depends on who's holding it

    • 41 Comments

    The Get­Current­Thread function returns a pseudo-handle to the current thread. The documentation goes into significant detail on what this means, but I fear that it may have fallen into the trap of providing so much documentation that people decide to skip it.

    Okay, so first of all, what is a pseudo-handle? a pseudo-handle is a sentinel value for HANDLE that is not really a handle, but it can act like one.

    The pseudo-handle returned by Get­Current­Thread means, "The thread that this code is running on." Note that this is a context-sensitive proposition. All the text in MSDN is explaining the consequences of that sentence.

    In a sense, the Get­Current­Thread function is like a GPS: It tells you were you are, not where you were.

    Imagine somebody who had never seen a GPS before. When they park their car in a parking garage, they look at the parking level number printed on the wall and write it down. Then when somebody asks, "Where did you park your car?" they can look in their notebook and say, "Oh, it's on level 3." Some parking garages even have little pads of paper with the parking level pre-printed on it. When you park your car, you tear a piece of paper off the pad and tuck it into your purse or wallet. Then when you want to return to your car, you see the slip of paper, and it tells you where you parked.

    Now suppose you hand that person a GPS device, and tell them, "This will tell you your current location."

    "Great! My current location is level 3 of the parking garage."

    They go out shopping or whatever they were planning on doing, and now it's time to go home. They can't remember where they parked, so they look at the device, and it says, "Your current location is 512 Main Street."

    "Hey, you told me this told me where I parked my car."

    "No, I said that it told your current location."

    "That's right. And at the time you gave it to me, my current location was level 3 of the parking garage. So I expect it to say 'Level 3 of the parking garage'."

    "No, I mean it tells you your current location at the time you look at it."

    "Well, that's stupid. I can do that too." (Scribble.) "There, it's a piece of paper that says 'You are right here'."

    The value returned by the Get­Current­Thread function is like the GPS, or the slip of paper that says "You are right here." When you hand that value to the kernel, it substitutes the current thread at the time you use it. It's like a check payable to Bearer: The money goes to whoever happens to take it to the bank.

    This means, for example, that if you call Get­Current­Thread from one thread and pass the result to another thread, then when that other thread uses the value, the kernel will interpret to mean the thread that is using it, not the thread that called Get­Current­Thread.

    It also means that the value cannot be meaningfully cached to remember the thread that created the value, because the point of Get­Current­Thread is to adapt to whoever happens to be using it.

    The theory behind Get­Current­Thread and its friend Get­Current­Process is that it gives you a convenient way to refer to the current thread from the current thread or the current process from the current process. For example, you might pass the return value of Get­Current­Process to Duplicate­Handle in order to duplicate a handle into or out of the current process. Or you might pass the return value of Get­Current­Thread to Set­Thread­Priority to change the priority of the current thread. The "current thread" pseudo-handle let you simplify this:

    BOOL SetCurrentThreadPriority(int nPriority)
    {
     BOOL fSuccess = FALSE;
     HANDLE hCurrentThread = OpenThread(THREAD_SET_INFORMATION,
                                FALSE, GetCurrentThreadId());
     if (hCurrentThread)
     {
      fSuccess = SetThreadPriority(hCurrentThread, nPriority);
      CloseHandle(hCurrentThread);
    }
    

    to

    BOOL SetCurrentThreadPriority(int nPriority)
    {
     return SetThreadPriority(GetCurrentThread(), nPriority);
    }
    

    If you want to convert a pseudo-handle to a real handle, you can use the Duplicate­Handle function.

    BOOL ConvertToRealHandle(HANDLE h,
                             BOOL bInheritHandle,
                             HANDLE *phConverted)
    {
     return DuplicateHandle(GetCurrentProcess(), h,
                            GetCurrentProcess(), phConverted,
                            0, bInheritHandle, DUPLICATE_SAME_ACCESS);
    }
    
    BOOL GetCurrentThreadHandle(BOOL bInheritHandle, HANDLE *phThread)
    {
     return ConvertToRealHandle(GetCurrentThread(), bInheritHandle, phThread);
    }
    
    BOOL GetCurrentProcessHandle(BOOL bInheritHandle, HANDLE *phProcess)
    {
     return ConvertToRealHandle(GetCurrentProcess(), bInheritHandle, phProcess);
    }
    

    Armed with your knowledge of pseudo-handles, criticize the following code:

    class CSingleThreadedObject
    {
    public:
     CSingleThreadedObject() : _hThreadCreated(GetCurrentThread()) { }
    
     bool OnCorrectThread() { return GetCurrentThread() == _hThreadCreated; }
    
    private:
     HANDLE _hThreadCreated;
    };
    
    class CFoo : protected CSingleThreadedObject
    {
    public:
     CFoo() { ... }
    
     // Every method of CFoo checks whether it is being called on the
     // same thread that it was created from.
    
     bool Snap()
     {
      if (!OnCorrectThread()) return false; // multithreading not supported
      ...
     }
    
    };
    

    Follow-up exercise: Criticize the following code that attempts to address the issues you raised in the previous exercise.

    // ignore error handling in this class for the purpose of the exercise
    class CSingleThreadedObject
    {
    public:
     CSingleThreadedObject() {
      ConvertToRealHandle(GetCurrentThread(), FALSE, &_hThreadCreated)
    }
    
     bool OnCorrectThread() {
      HANDLE hThreadCurrent;
      ConvertToRealHandle(GetCurrentThread(), FALSE, &hThreadCurrent);
      bool onCorrectThread = hThreadCurrent == _hThreadCreated;
      CloseHandle(hThreadCurrent);
      return onCorrectThread;
     }
    
    private:
     HANDLE _hThreadCreated;
    };
    
  • The Old New Thing

    Is there a way to disable a specific balloon notification without disabling all of them?

    • 11 Comments

    There is a group policy called Turn off all balloon notifications, but what if you want to turn off only one specific notification?

    The taskbar does not offer fine-grained policy control over balloon notifications. All you have is the giant sledgehammer that turns off all of them. If there is a specific balloon you want to disable, you have to check with the specific program that is raising them, or the specific product feature, to see if it offers a way to turn the balloon off.

    For example, there is a setting to disable the low disk space checks and another one to disable notifications that tell you when you have lost the connection to a networked file and are working on the local copy.

  • The Old New Thing

    Enumerating notification icons via UI Automation

    • 19 Comments

    Today's Little Program uses accessibility to enumerate the current notification icons (and possibly click on one of them). This could be done manually via IAccessible, but the BCL folks conveniently created the System.Windows.Automation namespace which contains classes that take a lot of the grunt work out of walking the accessibility tree.

    While it's true that the System.Windows.Automation namespace takes a lot of the grunt work out of accessibility, it is still rather verbose, so I'm going to start with some helper functions. They're all one-liners since they simply pass their parameters through with a little bit of extra typing.

    using System.Collections.Generic;
    using System.Windows.Automation;
    using System.Linq;
    
    static class AutomationElementHelpers
    {
     public static AutomationElement
     Find(this AutomationElement root, string name)
     {
      return root.FindFirst(
       TreeScope.Descendants,
       new PropertyCondition(AutomationElement.NameProperty, name));
     }
    

    The Automation­Element.Find extension method searches for a descendant of an accessible element with a particular name.

     public static IEnumerable<AutomationElement>
     EnumChildButtons(this AutomationElement parent)
     {
      return parent == null ? Enumerable.Empty<AutomationElement>()
                            : parent.FindAll(TreeScope.Children,
        new PropertyCondition(AutomationElement.ControlTypeProperty,
                              ControlType.Button)).Cast<AutomationElement>();
     }
    

    The Automation­Element.Enum­Child­Buttons extension method enumerates the button controls which are immediate children of a parent element.

     public static bool
     InvokeButton(this AutomationElement button)
     {
      var invokePattern = button.GetCurrentPattern(InvokePattern.Pattern)
                         as InvokePattern;
      if (invokePattern != null) {
       invokePattern.Invoke();
      }
      return invokePattern != null;
     }
    }
    

    The Automation­Element.Invoke­Button extension method checks if the element is invokable (which buttons are), and if so invokes its default action.

    Okay, given those helpers, we can write the actual enumerator.

    class Program {
    
     public static IEnumerable<AutomationElement> EnumNotificationIcons()
     {
      foreach (var button in AutomationElement.RootElement.Find(
                      "User Promoted Notification Area").EnumChildButtons()) {
       yield return button;
      }
    
      foreach (var button in AutomationElement.RootElement.Find(
                    "System Promoted Notification Area").EnumChildButtons()) {
       yield return button;
      }
    
      var chevron = AutomationElement.RootElement.Find("Notification Chevron");
      if (chevron != null && chevron.InvokeButton()) {
       foreach (var button in AutomationElement.RootElement.Find(
                          "Overflow Notification Area").EnumChildButtons()) {
        yield return button;
       }
      }
     }
    

    Okay, here's what's going on.

    First, we enumerate all the buttons that are children of an object called User Promoted Notification Area.

    Next, we enumerate all the buttons that are children of an object called System Promoted Notification Area. This object is usually empty, but it may contain an icon if a demoted icon is temporarily promoted because it is showing a balloon.

    Finally, if we are asked to enumerate hidden icons, we also find the Notification Chevron button and push it. That pops up a dialog called Overflow Notification Area, and we enumerate all the buttons from that dialog as well.

    Okay, let's take this function out for a spin.

     public static void Main()
     {
      foreach (var icon in EnumNotificationIcons())
      {
       var name = icon.GetCurrentPropertyValue(AutomationElement.NameProperty)
                  as string;
       System.Console.WriteLine(name);
       System.Console.WriteLine("---");
      }
     }
    }
    

    When you run this program, it should print the names of all the icons in your notification area, including the hidden ones (for which it needs to open the overflow dialog).

    You may have noticed that it takes a long time to generate the icons in the System Promoted Notification Area; that's because the accessibility system is going crazy looking for something that usually doesn't exist. Let's speed things up by reducing the scope of the search. Once we find the User Promoted Notification Area, we will search for the System Promoted Notification Area inside the same window. That should save a lot of time.

    // in static class AutomationElementHelpers
    
     static public AutomationElement
     GetTopLevelElement(this AutomationElement element)
     {
      AutomationElement parent;
      while ((parent = TreeWalker.ControlViewWalker.GetParent(element)) !=
           AutomationElement.RootElement) {
       element = parent;
      }
      return element;
     }
    

    The Automation­Element.Get­Top­Level­Element extension method walks up the control view and returns the ancestor element that is a direct child of the root.

     public static IEnumerable<AutomationElement> EnumNotificationIcons()
     {
      var userArea = AutomationElement.RootElement.Find(
                      "User Promoted Notification Area");
      if (userArea != null) {
       foreach (var button in userArea.EnumChildButtons()) {
        yield return button;
       }
    
       foreach (var button in userArea.GetTopLevelElement().Find(
                     "System Promoted Notification Area").EnumChildButtons()) {
         yield return button;
       }
      }
    
      var chevron = AutomationElement.RootElement.Find("Notification Chevron");
      if (chevron != null && chevron.InvokeButton()) {
       foreach (var button in AutomationElement.RootElement.Find(
                          "Overflow Notification Area").EnumChildButtons()) {
        yield return button;
       }
      }
     }
    

    Of course, what's the point of enumerating the icons if you can't also click them? Let's go look for the volume control icon and click it.

     public static void Main()
     {
      foreach (var icon in EnumNotificationIcons())
      {
       var name = icon.GetCurrentPropertyValue(AutomationElement.NameProperty) as string;
       if (name.StartsWith("Speakers:")) {
        icon.InvokeButton();
        break;
       }
      }
     }
    

    So far, this program relies on the accessible tree structure used by Windows 7 and Windows 8. If you run the program on earlier versions of Windows (or later ones), it may not work. That's because the accessible tree changed. The accessibiliy tree is not part of the API. It's something that is exposed for accessibility purposes to the end user, and the fact that there is a programmatic interface to it is an artifact of the accessibility.

    In Windows Vista, there is not a separate overflow area for notification icons. Instead, you use the chevron button to expand or contract the notification area. Let's tweak our program to work on Windows Vista instead of Windows 7:

     public static IEnumerable<AutomationElement> EnumNotificationIcons()
     {
      var userArea = AutomationElement.RootElement.Find("Notification Area");
      if (userArea != null) {
       // If there is a chevron, click it. There may not be a chevron if no
       // icons are hidden.
       var chevron = userArea.GetTopLevelElement().Find("NotificationChevron");
       if (chevron != null) {
        chevron.InvokeButton();
       }
       foreach (var button in userArea.EnumChildButtons()) {
        yield return button;
       }
      }
     }
    

    The name of the notification area in Windows Vista is simply Notification Area, and the name of the chevron is Notification­Chevron with no space. (Somebody was apparently trying to save two bytes.)

    Okay, now that you see the general idea, I'll leave Windows XP, Windows 2000, and Windows NT support as an exercise.

  • The Old New Thing

    Some parts of an interface can change but others can't

    • 25 Comments

    When I wrote about asking the compiler to answer calling convention questions, some people were concerned about whether this was a reliable mechanism or whether it was relying on something that can change in the future.

    This is a special case of the question, "What parts of an interface can change, and what can't?" And it all boils down to compile-time versus run-time.

    Assuming you are interested in binary compatibility (as opposed to merely source compatibility), then a decision made at compile-time can never be changed because the decision is already hard-coded into the application. For example, if you have a function that takes a parameter that is an enumeration, say,

    enum FOO_OPTIONS
    {
        FOO_HOP = 0,
        FOO_SKIP = 1,
        FOO_JUMP = 2,
    };
    

    then the values of FOO_HOP, FOO_SKIP, and FOO_JUMP are hard-coded into any program that uses them. The compiler will generate code like this:

    ; foo(FOO_JUMP);
    
        push 2
        call foo
    

    Suppose you later change the header file to

    enum FOO_OPTIONS
    {
        FOO_HOP = 2,
        FOO_SKIP = 3,
        FOO_JUMP = 4,
    };
    

    Making a change in the new version of a header file has no effect on any existing programs which were compiled with the old version of the header file. There is no way for the foo function to tell whether the 2 it received as a parameter is a FOO_JUMP from the old header file or a FOO_HOP from the new one.

    Therefore, you cannot reuse values in any existing enumerations or #define's because the values are already compiled into existing programs. If you had given the value 2 different meanings in different versions of the header file, you would have in principle no way of knowing which header file the caller used. Of course, you can invent external cues to let you figure it out; for example, there may be a separate set_foo_version function that callers use in order to specify whether they are using the old or new header file. Of course, that also means that if there are multiple components that disagree on what version of foo they want, you have another problem.

    Note that this is not the same as saying that the value of a symbol cannot change. We've seen this happen in the past with the PSH_WIZARD­97 flag, but these sorts of redirections are rare in practice.

    Another thing that is hard-coded into an application is the calling convention. Once code is generated by the compiler to call a function, that's that. You can't change the calling convention without breaking existing code. That's why you can ask the compiler, "How would you call this function?" and trust the answer: If the compiler generates code to call the function using technique X (register set-up, what gets pushed on the stack first, etc.), then the function had better accept technique X in perpetuity. Of course, you need to be sure that what you observe is in fact all there is. There may be parts of the calling convention that are not obvious to you, such as the presence of a red zone or maintaining a particular stack alignment. Or it could be that the function is called only from within the module, and the compiler's whole-program optimization decided to use a custom nonstandard calling convention.

    On the other hand, things determined at run-time can be changed, provided they are changed in a manner consistent with their original documentation. For example, the message numbers returned by Register­Window­Message can change because the documentation specifically requires you to call Register­Window­Message to obtain the message number for a particular named message.

    If you want to know how to call a function, it's perfectly valid to ask the compiler, because at the end of the day, that's how the function gets called. It's all machine code. Whether that machine code was generated by a compiler or by an assembler is irrelevant.

    Caveat: I'm ignoring whole-program optimization and link-time code generation, which allow the toolchain to rewrite calling conventions if all callers can be identified. We'll see more about this in a future article. The technique described in this article works best with exported/imported functions, because it is not possible to identify all callers of such functions, and the compiler is forced to use the official calling convention. (You can also use it when inspecting .COD files for functions defined in a separate translation unit, for the same reason. That's the technique I used in the linked article.)

  • The Old New Thing

    Why is there a 64KB no-man's land near the end of the user-mode address space?

    • 29 Comments

    We learned some time ago that there is a 64KB no-man's land near the 2GB boundary to accommodate a quirk of the Alpha AXP processor architecture. But that's not the only reason why it's there.

    The no-man's land near the 2GB boundary is useful even on x86 processors because it simplifies parameter validation at the boundary between user mode and kernel mode by taking out a special case. If the 64KB zone did not exist, then somebody could pass a buffer that straddles the 2GB boundary, and the kernel mode validation layer would have to detect that unusual condition and reject the buffer.

    By having a guaranteed invalid region, the kernel mode buffer validation code can simply validate that the starting address is below the 2GB boundary, then walk through the buffer checking each page. If somebody tries to straddle the boundary, the validation code will hit the permanently-invalid region and fail.

    Yes, this sounds like a micro-optimization, but I suspect this was not so much for optimization purposes as it was to remove weird boundary conditions, because weird boundary conditions are where the bugs tend to be.

    (Obviously, the no-man's land moves if you set the /3GB switch.)

  • The Old New Thing

    Standard handles are really meant for single-threaded programs

    • 19 Comments

    When I discussed the conventions for managing standard handles, Sven2 noted that I implied that you need to call Set­Std­Handle with a new handle if you close the current handle and asked "Wouldn't it make more sense to call it the other way round? I.e., first set the new handle, then close the old one? It would ensure that any other thread that runs in parallel won't get an invalid handle."

    Yes, that would make more sense, but only by a little bit. If you have one thread changing a standard handle at the same time another thread tries to use it, you still have the race condition, as Cesar noted, where the thread that gets the standard handle gets the handle closed out from under it. So you still have a race condition. All you did was narrow the window a little bit.

    This is basically a fundamental limitation of the standard handles. They are a shared process-wide resource, and if you're going to be mucking with them from multiple threads, it's your responsibility to apply whatever synchronization you need in order to avoid the problems associated with messing with process-wide resources. (This is similar to the problem with inherited handles and Create­Process.)

    The most common way of ensuring that one thread doesn't change a standard handle while another thread is using it is simple: Never change a standard handle. Consider standard handles a setting provided by the parent process. If the parent process says that standard output should go to a particular place, then send it to that place. Don't try to override the decision and send it somewhere else.

    If you really must change a standard handle, you'd be best off doing so right at the start before you start kicking off background threads. Another model you might try is to treat the initial thread as the "console UI thread" and make that the only thread that can communicate with the standard handles. Background threads can do work, but if they want to write to standard output or read from standard input, they need to ask the main thread to do it. This is probably a good plan anyway, because it avoids messy interleaved output as well as confusing input. (If two threads read from standard input at the same time, it's not clear to the user which thread their input will go to.)

    Personally, I would recommend combining both approaches: (1) Never change a standard handle, and (2) Restrict all usage of standard handles to your main thread to avoid problems with interleaving.

  • The Old New Thing

    Microspeak: All-up

    • 15 Comments

    Here are some citations. Let's see if we can figure out what it means.

    I think a presentation of these results would be a fun boost for the team. Is this something we should handle in a bunch of teams' weekly meetings, or should we do something all up?

    In the first citation, all up appears to mean "with everybody all together."

    We're looking for an all-up view of the various compatibility mitigations we have related to this feature.

    In the second citation, all up could mean "overview" or "detailed summary". Not sure yet. Let's keep looking.

    From the all up performance effort, we've settled on the approach below.

    Okay, this seems to suggest that all up refers to an aggregation of individual items. Let's try again:

    We have a number of channels for disseminating information. I think an all up destination could play a key and proactive role in major announcements such as the one from last week.

    Here, all up appears to mean "consolidated, comprehensive". Let's keep going.

    Document title: XYZ All Up Glossary

    This document is a glossary. Presumably is a glossary of terms you may encounter throughout the entire XYZ project. One last citation, this from a status report:

    • This week: Created Customer All up report.
    • Next week: Update Customer all up report with more customer related information.

    Okay, this didn't actually tell me much about what an all up report is, which is kind of a bummer because I was asked to create an all up report, and I still don't know if what I created is what the person wanted.

    (I ended up creating a report that summarized the status of every team, and called out issues that were noteworthy or reasons for concern. The person who asked for the report didn't complain, so I guess that was close enough to what they wanted that they didn't bother asking for more.)

Page 1 of 434 (4,331 items) 12345»