• The Old New Thing

    How can I make sure my program is launched only from my helper program and no other parent?

    • 40 Comments

    Say you have a collection of programs which work together. One of them is the "master" program that runs the show, and it has a bunch of "assistant" programs that it launches to accomplish various subtasks. These assistants are not meant to be run by themselves; they are meant to be run only by the master program. How do you design the assistant so that it can only be run by the master?

    There's nothing you can do to force the assistant to be run only by the master, since anything you do to detect the case can be faked out by an attacker. (Worst case is that they just run your program under the debugger and patch out the code that looks for the master.) So the purpose of this test is not so much to create an airtight hatchway as it is to prevent users from randomly wandering into the Program Files directory and double-clicking stuff to see what happens.

    The simplest way of doing this is to require a command-line parameter that the master passes to say, "Hey, it's me, the master. It's okay to do that thing you do." The command line parameter could be anything. assistant.exe /run say. If the command line parameter is not present, then the assistant says, "Um, please don't run this program directly. Use the master."

    You might decide to get really fancy and make the secret handshake super-complicated, but remember that there is no added security benefit here. The user can compromise assistant.exe by simply attaching a debugger to it, at which point any defensive mechanism you create can simply be disabled by a sufficiently-resourceful attacker. (And there's a class of people who will see that you put a lot of work into protecting your assistant, and that will just convince them to work harder to circumvent the protection. Because something with this much protection must certainly be very valuable!)

    There's also a benefit to keeping the secret handshake simple: It makes it a lot easier for you to debug the assistant program. Instead of having to set up the master and then get the master to do all the things it needs to generate the secret handshake for the assistant, you can just run your assistant directly with the magic flag, and boom, you're off and debugging.

    To make it even harder to run your program by accident, you can give it an extension that is not normally executable, like .MOD. That way, it cannot be double-clicked, but you can still pass it to Create­Process or (with some cajoling) Shell­Execute­Ex.

  • The Old New Thing

    What is the programmatic equivalent to unchecking the box to prevent a file from having its contents indexed?

    • 25 Comments

    A customer wanted to know how they could write a program that automatically checked and unchecked the box that appears on a file's property sheet on the General tab, clicking the Advanced button, and then checking or unchecking the item whose name keeps changing:

    • On Windows 7, it's called Allow this file to have contents indexed in addition to file properties.
    • On Windows Vista, it's called Index this file for faster searching.
    • On Windows 2000 and Windows XP, it's called For fast searching, allow Indexing Service to index this folder.

    The checkbox maps to the file attribute formally known as FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, and informally known as FANCI (pronounced like the word fancy). Checking the box clears the attribute, and unchecking the box sets the attribute.

    The customer liaison replied, "Thanks for your assistance. The customer was able to use the System.IO.File.Set­Attributes method with the values in the System.IO.File­Attributes enumeration to manipulate the indexing attribute. The customer has a follow-up question, however: ‘I need this change to be applied recursively to all files in a entire directory subtree. Is there a single series of Visual Basic commands that will accomplish this, or do I need to write a loop by hand?’"

    This question kind of ran off topic for the product team and fell more in line with Developer Support. I suggested that the follow-up question be redirected to the Visual Basic support team.

    For me, it was interesting that (1) the customer liaison was himself not aware enough to realize that the question had changed audiences, and (2) the customer was so helpless that they couldn't look for the answer themselves.

    Bonus chatter: The file system itself pays no attention to the FANCI bit. It's just a signal to any program that does file content indexing that this particular file should be skipped. Whether any particular search index program respects the flag is something you need to take up with the vendor of that search index program. (As far as I'm aware, all Microsoft search indexes should honor the flag.)

  • The Old New Thing

    When will the static control automatically delete the image loaded into it, and when is it the responsibility of the application?

    • 25 Comments

    If you create a static control with initial contents (for example, by creating a BITMAP or ICON control in a dialog template), then the static control will load the contents upon creation and destroy the contents upon destruction. So at least in the case where you don't touch the static control, things will work automatically.

    But once you touch it, things get confusing.

    If you send the STM_SET­IMAGE message to a static control, this does a few things (assuming your parameters are all valid):

    • The previous image is replaced by the new image you passed.
    • The message returns a handle to the previous image.
    • The static control turns off automatic image deletion.

    The third part is the tricky part. If you ever (successfully) send a static control the STM_SET­IMAGE message, then it says, "Okay, it's all your problem now." You are now responsible not only for destroying the new image, but you are also responsible for destroying the old image that was returned.

    In other words, the following operation is not a nop:

    HBITMAP hbmPrev = SendMessage(hwndStatic, STM_SETIMAGE,
                                  IMAGE_BITMAP, (LPARAM)hbmNew);
    SendMessage(hwndStatic, STM_SETIMAGE,
                IMAGE_BITMAP, (LPARAM)hbmPrev);
    

    This sounds like a nop, since all you did was change the image, and then change it back. But the side effect is also that you made the static control go into your problem mode, and the original image will no longer be automatically destroyed. If you forget to destroy it yourself, then you have a leak.

    Wait, it gets worse.

    If you are using version 6 of the common controls, then things get even more confusing if you use the STM_SET­IMAGE message to change the IMAGE_BITMAP of a SS_BITMAP static control, and the bitmap you pass is a 32-bpp bitmap, and the image has a nonzero alpha channel, then the static control will make a copy of the bitmap you passed in and act as if you had passed that copy instead.¹ This by itself is no big deal, because the responsibility for destroying the image you passed in still resides with you, the application, so the rules haven't changed there.

    The nasty bit is that the application also must assume responsibility for destroying the secret copy. That bitmap you didn't even know existed and don't have a handle to? Yeah, you're on the hook for that one too.

    How unfair.

    Even more confusing is that if you send STM_SET­IMAGE a second time, it will replace the bitmap and return a handle to the secret copy (which is a bitmap you've never seen before).

    This means that the following assertion can fire:

    HBITMAP hbmPrev = SendMessage(hwndStatic, STM_SETIMAGE,
                                  IMAGE_BITMAP, (LPARAM)hbmNew);
    HBITMAP hbmBack = SendMessage(hwndStatic, STM_SETIMAGE,
                                  IMAGE_BITMAP, (LPARAM)hbmPrev);
    assert(hbmNew == hbmBack); // ??
    

    You would think that the assertion is safe because all you did was change the bitmap to hbmNew, then change it back. And when you change it back, the "previous value" is the value hbmNew you set it to on the previous line.

    Except that if hbmNew satisfies the above magic criteria, then the value in hbmBack is not hbmNew but rather the handle to the secret copy.

    Which you have to remember to destroy.

    Yuck.

    The secret copy is not too secret. You can get a handle to it by sending the STM_GET­IMAGE message. Which you now need to do when you destroy the static control, just in case it's the secret copy. You need to compare the current image against the one that you thought you passed in, and if they are different, then you have the secret copy that needs to be destroyed as an extra step.

    Yes, this sucks. I apologize.

    (My recommendation: To detect whether a "secret copy" occurred, do a STM_GET­IMAGE after your STM_SET­IMAGE and see if the handles match.)

    ¹ The secret copy is not an exact copy. (After all, if it were an exact copy, then there would be no need to create the copy. It could just use the handle you passed in.) Instead, the secret copy is a copy of the original, followed by some additional munging so that it can be displayed on the screen while respecting the alpha channel you passed in.

  • The Old New Thing

    If you cancel an operation while it's in progress, then it's not surprising that it's only half-done

    • 65 Comments

    A customer (via their customer liaison) started by asking why they were seeing an unexpected access control entry in the security descriptor of an object.

    The ACEs on the parent grant access to Administrators, CREATOR OWNER, SYSTEM, and Users, but the ACEs on the child object (which should simply have been inherited from the parent) include an extra entry for Bob. How did Bob get access to the child object? When we view the details of the ACEs, it lists the Bob entry as Inherited from parent. But there is no Bob entry in the parent!

    I observed, "Probably because Bob is the CREATOR OWNER."

    Thanks for the explanation, but even if Bob is the CREATOR OWNER, how can we explain that the permission is inherited from the parent?

    The permission is inherited from the parent because the parent has specified the rights of the CREATOR OWNER, and Bob is the creator/owner. As part of the inheritance process, the rights of the CREATOR OWNER get assigned to Bob.

    Remember that CREATOR OWNER is not a real person. It is a placeholder that gets replaced with the actual creator/owner when the object is created. If Bob created the child object, then the permissions of CREATOR OWNER will be given to Bob on the child object.

    The CREATOR OWNER is not a live entry that dynamically updates to match the current creator/owner. It is a static entry that is assigned at the point of creation. Changes to the owner in the future have no effect because the identity has already been snapshotted. (I think a less confusing name would have been simply OBJECT CREATOR, since creation happens only once.)

    (Note that there is a little extra weirdness here: If the creator is a member of the Administrators group, then the CREATOR OWNER rights get assigned to the entire Administrators group instead of the specific user who created it. You can change this behavior by tweaking the Default owner for objects created by members of the Administrators group policy.)

    The customer liaison conferred with the customer, and determined that, at least in one of the cases they were studying, Bob was not the original creator.

    What actually happened was that at some point, Bob was granted access to the parent object and all its sub-objects. Later, somebody went back to the parent object and told it to revoke Bob's access to the parent object and all its sub-objects. But "If we cancel the process fast enough, then we get the strange behavior as originally described."

    Well, duh!

    You asked for Bob's access to the parent object and all its sub-objects to be revoked, so the tool you used started a recursive tree walk from the parent object looking for any objects that Bob has access to and removing them. But if you cancel the operation partway through, then that tool didn't get a chance to finish the job, and you obviously are left in a situation where Bob's access was only partially revoked.

    The customer liaison confirmed,

    Yes, that's what happened.

    It's nice of the customer liaison to confirm the diagnosis, but it still baffles me that they were confused by this in the first place.

    To me this is one of those So what did you expect type of situations. You start an operation, then partway through, you cancel it, and then you're surprised that the operation did not run to completion.

  • The Old New Thing

    The Grand Duke's monocle is an affectation

    • 10 Comments

    In the Disney adaptation of Cinderella, the Grand Duke wears a monocle. The monocle moves from eye to eye during the course of the story.

    The Grand Duke's monocle is an affectation.

    Either that, or he needs a full pair of glasses, but is very frugal.

  • The Old New Thing

    Writing automation to wait for a window to be created (and dismiss it)

    • 18 Comments

    Today's Little Program uses UI Automation to cancel the Run dialog whenever it appears. Why? Well, it's not really useful in and of itself, but it at least provides an example of using UI Automation to wait for an event to occur and then respond to it.

    using System.Windows.Automation;
    
    class Program
    {
     [System.STAThread]
     public static void Main(string[] args)
     {
      Automation.AddAutomationEventHandler(
       WindowPattern.WindowOpenedEvent,
       AutomationElement.RootElement,
       TreeScope.Children,
       (sender, e) => {
        var element = sender as AutomationElement;
        if (element.Current.Name != "Run") return;
    
        var cancelButton = element.FindFirst(TreeScope.Children,
         new PropertyCondition(AutomationElement.AutomationIdProperty, "2"));
        if (cancelButton != null) {
         var invokePattern = cancelButton.GetCurrentPattern(InvokePattern.Pattern)
                             as InvokePattern;
         invokePattern.Invoke();
         System.Console.WriteLine("Run dialog canceled!");
        }
       });
      System.Console.ReadLine();
      Automation.RemoveAllEventHandlers();
     }
    }
    

    Okay, let's see what's going on here.

    The program registers a delegate with UI automation which is called for any Window­Opened event that is an immediate child (Tree­Scope.Children) of the root (Automation­Element.Root­Element). This will catch changes to top-level unowned windows, but not bother firing for changes that occur inside top-level windows or for owned windows.

    Inside our handler, we check if the window's title is Run. If not, then we ignore the event. (This will get faked out by any other window that calls itself Run.)

    Once we think we have a Run dialog, we look for the Cancel button, which we have determined by using UI Spy to have the automation ID "2". (That this is the numeric value of IDCANCEL is hardly a coincidence.)

    If we find the Cancel button, we obtain its Invoke pattern so we can Invoke it, which for buttons means pressing it.

    Take this program out for a spin. Run the program and then hit Win+R to open the Run dialog. Oops, the program cancels it!

    Ha-ha!

  • The Old New Thing

    When someone proposes marriage, bear in mind that there is a question that needs to be answered

    • 31 Comments

    A colleague of mine was at a restaurant, and he spotted a young couple at the next table. The woman fawned over a classic diamond engagement ring, and when she put it on her finger, he decided that it was safe to ask them about it.

    They had gotten engaged earlier that day, and the man told the story of the proposal, up to the point where he asked her to marry him.

    My colleague then turned to the woman and teasingly asked, "And what did you say?"

    The woman chuckled, then suddenly her eyes opened wide with the realization that she had skipped over this important technical detail. She became dead serious and very, very clearly said to the man seated across the table from her, "Yes."

    My colleague paid for their dinner.

    Related story: When I proposed to my wife, the first three things she said were, "What are you doing?", "What's this?", and "Oh, my God!"

    If all you knew was that these three sentences were uttered in response to a marriage proposal, it would be difficult to determine with certainty whether the proposal was accepted or rejected.

    Fortunately for me, it went well, but after the hugging and kissing, I had to remind her, "You haven't answered the question yet."

  • The Old New Thing

    Debugging: Diagnosing why malloc is failing

    • 14 Comments

    A customer had some code which was experiencing memory allocation failures when calling malloc (which maps to Heap­Alloc). The function returns nullptr, and Get­Last­Error() reports ERROR_NOT_ENOUGH_MEMORY. However, there was still plenty of memory free:

    • Task Manager reported working set at around 400MB, with a peak of 550MB.
    • Using the _heap­walk function to compute the total memory used resulted in about 380MB being reported.
    • The _heap­chk function reported no errors.
    • The virtual memory size for the process was a little bit more than the working set size.

    The customer was continuing their investigation but was looking for some pointers since the bug took a day to emerge. Could it be heap fragmentation? (The program is uses the regular C runtime heap and does not enable the low-fragmentation heap.)

    One of the suggestions was to run the VMMap utility to see if the problem was exhaustion of virtual address space.

    And lo and behold, that was indeed the cause. The code had a bug where it was leaking threads. Since the default stack reservation for a thread is 1MB (although typically only a tiny fraction of that ends up being committed and even less being charged against working set), a slow accumulation of threads corresponds to a slow erosion of the virtual address space until you eventually run out.

    Once again, it's the address space, stupid.

  • The Old New Thing

    When something gets added to a queue, it takes time for it to come out the front of the queue

    • 9 Comments

    A customer wanted to know why the input they were simulating with Send­Input is not being reported by Get­Async­Key­State. Isn't that supposed to reflect the instantaneous keyboard state? I just pushed the key down (or at least simulated it), but when I ask if the key is down, I'm told "Nope." What's the deal?

    INPUT input = { 0 };
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = 'A';
    input.ki.wScan = 'A';
    input.ki.dwFlags = 0; // key down
    SendInput(1, &input, sizeof(INPUT));
    
    assert(GetAsyncKeyState('A') < 0);
    

    The Send­Input call simulates pressing the A key, and the code immediately checks whether the key is down.

    But sometimes the assertion fires. How can that be?

    Because you're asking the question before the window manager has fully processed the input. Here's a little diagram.

    Mouse Keyboard Hardware
    SendInput Hardware
    Input
    Queue
     
    Dequeue
    Raw Input Thread
    Low
    Level
    Hooks
    Applications
    Update
    Input
    State
    Raw Input Thread
    App 1 App 2 App 3

    When you call Send­Input, you're putting input packets into the system hardware input queue. (Note: Not the official term. That's just what I'm calling it today.) This is the same input queue that the hardware device driver stack uses when physical devices report events.

    The message goes into the hardware input queue, where the Raw Input Thread picks them up. The Raw Input Thread runs at high priority, so it's probably going to pick it up really quickly, but on a multi-core machine, your code can keep running while the second core runs the Raw Input Thread. And the Raw Input thread has some stuff it needs to do once it dequeues the event. If there are low-level input hooks, it has to call each of those hooks to see if any of them want to reject the input. (And those hooks can take who-knows-how-long to decide.) Only after all the low-level hooks sign off on the input is the Raw Input Thread allowed to modify the input state and cause Get­Async­Key­State to report that the key is down.

    And if you manage to look before all this happens, your code will see that the key isn't down yet.

    It's like dropping a letter in the mailbox and then calling somebody to say, "Did you get my letter yet?" Okay, the Raw Input Thread is faster than the Postal Service, but you still have to give it a chance to get the message, query each of the low-level input hooks, decide who the message should be delivered to, and put it in their message queue.

  • The Old New Thing

    The heavy metal umlaut encroaches into Seattle real estate

    • 29 Comments

    The heavy metal umlaut is creeping into Seattle real estate.

    I submit for your consideration the condominium known as Bleü. I can't even tell what language they are trying to pretend to be.

    There are other properties in Seattle with dots, but at least the dots aren't gratuitous.

    Hotel Ändra in Belltown takes its name from the Swedish word meaning to change. (The hotel is consistent with its use of the dots, but outsiders frequently omit them, changing the hotel's name to Andra, which means "Others".)

    Hjärta Condos takes its name from the Swedish word meaning heart. Hjärta is in the Ballard neighborhood, the traditional center of Scandinavian life in Seattle. (The people who run the Web site can't seem to remember to put the dots over the a. They often spell it Hjarta, which is not a word in Swedish.)

    Note that in Swedish, the dots over the a and o are not umlauts nor are they diaereses. They're just dots. The ä and ö are not variants of a and o; they are letters in their own right. Sort of how like Q and R are like O and P with a tail, but nobody thinks of them as related letters. It's just a superficial graphical similarity.

Page 6 of 419 (4,184 items) «45678»