• The Old New Thing

    How do you prevent the linker from discarding a function you want to make available for debugging?

    • 22 Comments

    We saw some time ago that you can ask the Windows symbolic debugger engine to call a function directly from the debugger. To do this, of course, the function needs to exist.

    But what if you want a function for the sole purpose of debugging? It never gets called from the main program, so the linker will declare the code dead and remove it.

    One sledgehammer solution is to disable discarding of unused functions. This the global solution to a local problem, since you are now preventing the discard of any unused function, even though all you care about is one specific function.

    If you are comfortable hard-coding function decorations for specific architectures, you can use the /INCLUDE directive.

    #if defined(_X86_)
    #define DecorateCdeclFunctionName(fn) "_" #fn
    #elif defined(_AMD64_)
    #define DecorateCdeclFunctionName(fn) #fn
    #elif defined(_IA64_)
    #define DecorateCdeclFunctionName(fn) "." #fn
    #elif defined(_ALPHA_)
    #define DecorateCdeclFunctionName(fn) #fn
    #elif defined(_MIPS_)
    #define DecorateCdeclFunctionName(fn) #fn
    #elif defined(_PPC_)
    #define DecorateCdeclFunctionName(fn) ".." #fn
    #else
    #error Unknown architecture - don't know how it decorates cdecl.
    #endif
    #pragma comment(linker, "/include:" DecoratedCdeclFunctionName(TestMe))
    EXTERN_C void __cdecl TestMe(int x, int y)
    {
        ...
    }
    

    If you are not comfortable with that (and I don't blame you), you can create a false reference to the debugging function that cannot be optimized out. You do this by passing a pointer to the debugging function to a helper function outside your module that doesn't do anything interesting. Since the helper function is not in your module, the compiler doesn't know that the helper function doesn't do anything, so it cannot optimize out the debugging function.

    struct ForceFunctionToBeLinked
    {
      ForceFunctionToBeLinked(const void *p) { SetLastError(PtrToInt(p)); }
    };
    
    ForceFunctionToBeLinked forceTestMe(TestMe);
    

    The call to Set­Last­Error merely updates the thread's last-error code, but since this is not called at a time where anybody cares about the last-error code, it is has no meaningful effect. The compiler doesn't know that, though, so it has to generate the code, and that forces the function to be linked.

    The nice thing about this technique is that the optimizer sees that this class has no data members, so no data gets generated into the module's data segment. The not-nice thing about this technique is that it is kind of opaque.

  • 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 the law says you can't file a petition, you might need to file it anyway, in case somebody later says that you should've even though the law says you couldn't

    • 9 Comments

    It sounds like a scene from the movie Brazil, but in fact it's the law.

    Let's rewind a bit. The introduction is a bit technical, but I'll try to keep it short.

    There is a legal filing known as a habeas petition and another known as a petition for review. There are rules regarding what each one covers and the deadlines for filing them. Prior to 2005, there was no deadline for habeas petitions, but you had to file your petition for review within 30 days of whatever it was the government did that you wanted to object to. In 2005, Congress passed (and the President signed) a law which recategorizes what the two types of filings covered, and many claims that had fallen under the habeas petition have been reclassified as requiring a petition for review instead.

    This change in the rules creates a gap in coverage because Congress forgot to include a grandfather clause (or, for computer geeks, a "smooth migration plan"): What if, at the time the new law took effect, the thing you want to complain about was reclassified as requiring a petition for review, but it took place more than 30 days ago? You wake up one morning and somebody tells you, "Hey, there's a new law today. You just lost your right to respond."

    What you do, then, is file a lawsuit challenging the new rules. And then two years later, the Third Circuit Court hears your case and rules that, yes, you're right, the law that Congress passed is unconstitutional (a violation of Section 9, Clause 2, known commonly as the Suspension Clause) because it denied you the opportunity to file a claim.

    And now here's the weird part.

    Instead of saying, "And therefore we strike down this part of the law as unconstitutional," the court says "And therefore we will retroactively rewrite the law so it is constitutional again (saving Congress and the President the trouble of having to do it themselves), and oh lookie here, according to this new law we just made up, you did have a constitutionally guaranteed opportunity to file your petition, but it expired two years ago."

    In other words, what you should have done in 2005 was hire a psychic, who would then instruct you to spend thousands of dollars hiring an attorney to draft and file a petition which, according to the law, you were legally barred from filing, in anticipation of the courts (two years later) rewriting the law in order to make that filing legal again. And then when you file your petition, you have to convince the court to accept it, explaining that yes, I know that I cannot legally file this petition, but a psychic told me to do it.

    You can read the court's decision yourself. (Despite the connotations associated with the term legalese, court decisions are actually quite readable. You just have to skip over the complicated footnotes.)

  • The Old New Thing

    Welcome Martyn Lovell

    • 0 Comments
    Martyn Lovell from the VC++ team has joined the world of blogging. Martyn is a smart guy, even though he does spell some words funny.
  • 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

    Sharktopus: Just when you thought it was safe to see what movies are coming out

    • 27 Comments

    Sharktopus: Half-shark. Half-octopus. All-killer.

    I am not making that up.

    The Web site is sharktopusmovie.com, presumably because sharktopus.com was already taken. I am not making that up.

    I guess they wanted to ride the coattails of Megashark vs. Giant Octopus?

    Even more disturbing discovery: Megashark vs. Giant Octopus has a sequel: Megashark versus Crocosaurus.

    One of my colleagues says that he's going to wait for the sequel: Sharktopuses on a Plane.

  • The Old New Thing

    What is the default cursor for a thread?

    • 21 Comments

    When we looked at the process by which the cursor is set, we neglected to discuss the case where nobody bothers to set the cursor. What is the ultimate default cursor?

    Let's write a program that refuses to set the cursor. Take the scratch program and add these lines:

    BOOL OnSetCursor(HWND hwnd, HWND hwndCursor,
                     UINT codeHitTest, UINT msg)
    {
      return TRUE;
    }
    
       HANDLE_MSG(hwnd, WM_SETCURSOR, OnSetCursor);
    

    What we did was make the window explicitly refuse to set the cursor by making it do nothing and return TRUE, which means, "It's all good. I set the cursor!" (Liar, liar, pants on fire.)

    Run this program, move the cursor over the window, and what do you get?

    The hourglass.

    Now, this is clearly some sort of pathological case, where there is a thread that covers its ears and hums whenever the window manager asks it to specify a cursor. But you can end up in this case unintentionally, and in fact there's a good chance that you've seen it happen. Just write an application that blocks the UI thread during startup. Take a fresh scratch program and add a different line of code:

            ShowWindow(hwnd, nShowCmd);
    
            Sleep(5000);
    
            while (GetMessage(&msg, NULL, 0, 0)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
    

    Here, we're simulating a program that hangs its UI thread during initialization. During that initial five-second delay, the program has yet to pump any messages, so it hasn't yet received the WM_MOUSE­MOVE or WM_NC­MOUSE­MOVE message that would normally trigger the WM_SET­CURSOR message. All the window manager can do is show the default cursor.

    That's why the default cursor is an hourglass.

  • The Old New Thing

    What is the effect of memory-mapped file access on GetLastError()?

    • 28 Comments

    A customer was using memory-mapped files and was looking for information as to whether access to the memory-mapped data modifies the value returned by Get­Last­Error. A member of the kernel team replied, "No, memory-mapped I/O does not ever change the value returned by Get­Last­Error."

    That answer is simultaneously correct and wrong, a case of looking at the world through kernel-colored glasses.

    While it's true that the kernel does not ever change the value returned by Get­Last­Error, it's also the case that you might change it.

    If you set up an exception handler, then your exception handler might perform operations that affect the last-error code, and those changes will be visible after the exception handler returns. (This applies to all exception handlers and filters, not just ones related to memory-mapped files.)

    If you intend to return EXCEPTION_CONTINUE_EXECUTION because you handled the exception, then you probably should make sure to leave the last-error code the way you found it. Otherwise, the code that you interrupted and then resumed will have had its last-error code changed asynchronously. You just sabotaged it from above.

    // Code in italics is wrong
    
    LONG ExceptionFilter(LPEXCEPTION_POINTERS ExceptionPointers)
    {
     if (IsAnExceptionICanRepair(ExceptionPointers)) {
       RepairException(ExceptionPointers);
       // fixed up error; continuing
       return EXCEPTION_CONTINUE_EXECUTION;
     }
    
     if (IsAnExceptionICanHandle(ExceptionPointers)) {
      // We cannot repair it, but we can handle it.
      return EXCEPTION_EXECUTE_HANDLER;
     }
    
     // Not our exception. Keep looking.
     return EXCEPTION_CONTINUE_SEARCH;
    }
    

    If the Is­An­Exception­I­Can­Repair function or Repair­Exception function does anything that affects the last-error code, then when the exception filter is executed for a repairable exception, the last-error code is magically changed without the mainline code's knowledge. All the mainline code did was execute stuff normally, and somehow during a memory access or a floating point operation or some other seemingly-harmless action, the last-error code spontaneously changed!

    If you are going to continue execution at the point the exception was raised, then you need to "put things back the way you found them" (except of course for the part where you repair the exception itself).

    LONG ExceptionFilter(LPEXCEPTION_POINTERS ExceptionPointers)
    {
     PreserveLastError preserveLastError;
    
     if (IsAnExceptionICanRepair(ExceptionPointers)) {
       RepairException(ExceptionPointers);
       // fixed up error; continuing
       return EXCEPTION_CONTINUE_EXECUTION;
     }
    
     if (IsAnExceptionICanHandle(ExceptionPointers)) {
      // We cannot repair it, but we can handle it.
      return EXCEPTION_EXECUTE_HANDLER;
     }
    
     // Not our exception. Keep looking.
     return EXCEPTION_CONTINUE_SEARCH;
    }
    

    Exercise: Why isn't it important to restore the last error code if you return EXCEPTION_EXECUTE_HANDLER?

    Exercise: Is it important to restore the last error code if you return EXCEPTION_CONTINUE_SEARCH?

  • The Old New Thing

    Why is the fine for a basic traffic infraction in the state of Washington such a random-looking number?

    • 39 Comments

    Willy-Peter Schaub was puzzled by a sign reminding drivers that the fine for obstructing an intersection is $101 and wonders what the extra $1 is for.

    The laws of the State of Washington defer the monetary value of traffic fines to the Infraction Rules for Courts of Limited Jurisdiction (more commonly known as the IRLJ), specifically section 6.2: Monetary Penalty Schedule for Traffic Infractions [pdf].

    But wait, the fine listed in the IRLJ is only $42. Where did $101 come from?

    In addition to the base fine in the IRLJ, RCW 3.62.090 specifies additional assessments: Section (1) specifies a 70% assessment for public safety and education, and section (2) specifies an additional public safety and education assessment equal to 50% of the earlier assessment. On top of that, RCW 46.63.110 specifies various fees and penalties: Section 7(a) specifies a $5 fee for emergency services, section 7(b) specifies a $10 fee for auto theft prevention, section 7(c) specifies a $2 fee for the traumatic brain injury account, and section 8(a) specifies a $20 penalty to be shared between the state and the local jurisdiction.

    There are probably other clauses which add to the fines and penalties. I remember investigating this a few years ago and convincing myself that after taking all the fines and penalties and assessments and whatever-else-they-call-its into account, the total did come to $101. (Actually, they bring it to something close to $101, and then another rule about rounding kicks in.)

    And you won't get the numbers to add up to $101 any more because there were changes to the fee schedule in July 2007. The fine for basic traffic infractions is now $124. The new calculation appears to be 42 × 2.05 + 5 + 10 + 2 + 20 = $123.10, which rounds up to $124.

  • The Old New Thing

    Alt text for images are important in email, too

    • 17 Comments

    Apparently the IT department gave up on getting everybody to read email in plain text, and other service departments at Microsoft have moved beyond simply using HTML for markup and started adding banner images to the top of each email message. Because the best way to promote your brand to other parts of the company is to stick a banner logo at the top of every message.

    Here's the HTML for one such banner image, with line breaks inserted for sanity.

    <img width=707 height=63 id="Picture_x0020_2"
    src="cid:image001.png@01CB0944.B4771400"
    alt="Description: Description: Description: Description:
    Description: Description: Description: Microsoft Real Estate
    and Facilities">
    

    The great thing about the absurd alt text is that that's what appears in the autopreview window and in the email notification pop-up.

    BUILDING NOTICE: Buildings 8...
    Description: Description: Description:
    Description: Description: Description:...

    But wait, it gets worse. The second image in the message (a giant circled-i icon indicating that this is an informational message) has as its alt text "Description: Description: Description: Description: Description: Description: cid:image003.jpg@01CAFC55.BC923A80". Yeah, like that explains the image clearly.

    Maybe they were just taking a lead from the boss.

    No lesson today, just venting.

Page 369 of 453 (4,528 items) «367368369370371»