• The Old New Thing

    Dr. Watson and the bluescreen - a story from the trenches

    • 14 Comments

    A fellow Microsoft employee volunteered a story from his prior work at a hospital as their enterprise architect.

    I received an escalation from our Tier 1 service desk on a Dr. Watson. Why would I get a simple escalation? Strange...

    Since I hadn't seen the outside of my cubicle for a while, I decided to walk over to talk to the customer in person.

    The employee having the problem was named Dr. Watson. His computer had bluescreened.

    I still get a chuckle out of that years later. That little unexpected name collision threw twelve people in the IT service and support teams into disarray.

  • The Old New Thing

    Well, duh, I'd sure better get my money back

    • 27 Comments

    The vending machines in my building proudly announce

    Guaranteed to deliver or your money back.

    Well, duh. If I don't get the product, I'd sure better get my money back.

    Pre-emptive snarky comment: "I'm suing Microsoft."

  • 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

    How do I disable windowless control support in dialog boxes?

    • 12 Comments

    A customer wanted to know how to disable windowless control support in dialog boxes. "The customer has a CommandButton ActiveX control on his dialog box, and using Get­Dlg­Item to get the window handle of the command button succeeded with VC 6.0, but when compiled with VC 9.0, it does not create a window. I'm guessing that this is caused by Dialog­Box's support for windowless controls. Is it possible to disable support for windowless controls?"

    The question on its face is somewhat puzzling, because dialog boxes don't "support" or "not support" windowless controls. It's like asking, "I want rice that doesn't support meat. My customer is a vegetarian and cannot eat meat." Rice doesn't support meat, and it doesn't not-support meat. If you don't want meat, then don't add meat. And if you don't want windowless controls on your dialog box, then don't create windowless controls.

    I was also not sure what the customer meant by CommandButton, because Win32 command buttons are not ActiveX controls. The customer must be referring to something else also called Command­Button, in which case the customer should also consult the documentation for that something else to see if there's a way to control its windowed/windowless behavior.

    The customer liaison gave some more details: "My customer uses Get­Dlg­Item to get the handle of a specific window. This method worked in VC 6.0 since VC 6.0 doesn't support windowless controls. But VC 9.0 added support for windowless controls in dialog boxes, which breaks my customer's code. Is there a way to disable support for windowless controls in dialog boxes?"

    It took a few more questions, but eventually we figured out that the customer was not using raw Win32 dialog boxes (as Dialog­Box suggested in the original question) but rather MFC dialog boxes, and the CommandButton in question is a Microsoft Forms 2.0 CommandButton control.

    "The customer simply wants to continue using his code without modification. He is already using the Microsoft Forms 2.0 CommandButton control, and he is already using Get­Dlg­Item to obtain its handle, but that technique no longer works."

    The pieces started to fall into place, and somebody from the Visual Studio team provided an explanation: The version of MFC which comes with Visual Studio 2000 added support for hosting windowless ActiveX controls. By default, the MFC hosting code permits controls to be added as windowless controls if the control requests it. To force all controls to be windowed, you need to provide a custom class which derives from COle­Control­Site and overrides IOle­In­Place­Site­Windowless::Can­Windowless­Activate to return S_FALSE. Then override the dialog's CWnd::Create­Control­Site method to return an instance of this class instead of the default control site.

    I haven't actually tested this to see if it works, but the customer didn't come back, so either it worked, or they decided that we were jerks and didn't want to waste their time with us any more.

  • 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

    Microspeak: Whale Boy

    • 9 Comments

    Today is the tenth anniversary of Windows Live Messenger. My colleague Danny Glasser provides some history behind the product, and you can watch a tenth anniversary celebration video created for the occasion. And thus is inspired today's Microspeak: Whale Boy.

    Whale Boy is the nickname for the pawn-shaped Messenger buddy icon. His normal state is green, but he changes color or picks up a piece of flair to indicate various changes in status, such as busy or away.

    I don't know the etymology of the term, but I suspect it came from his somewhat rotund appearance.

    Sample usage (which I made up just now; not from an actual document): "Why don't we light up Whale Boy when the user regains connectivity?"

    Bonus Microsoft trivia: At timecode 3:40 in the video (spoiler alert!) Steve Liffick presents Whale Boy with a strange glass object. That is the Microsoft ten-year service award. Stick around for 25 years and collect the entire set!

  • The Old New Thing

    Whoa there, logging on awful fast now are we?

    • 16 Comments

    Occasionally, a customer will run into a problem that manifests itself only when Autologon is enabled. Here are some examples:

    If we log on manually, everything works just fine. But if we log on using Autologon with the same userid and password, we get a networking error from our wireless network card. Is there a known problem with Autologon and wireless networking?
    If we log on manually, everything works just fine. But if we log on using Autologon with the same userid and password, one of the programs in the Startup group raises an error because it can't create a remote desktop session.

    The issue really isn't Autologon. The issue really is the manual logon. For you see, manually logging on takes time. If you really concentrate you can get it down to one or two seconds, but under more realistic circumstances, a manual logon will be significantly slower than an automatic one because it simply takes time to click and type and click. And those seconds are crucial.

    That extra time, the delay introduced by the fact that human beings type a lot more slowly than a computer can, is enough to get those services you are relying fully initialized by the time you need them. Locating and connecting to a nearby wireless access point typically takes several seconds. If you use Autologon, the system will plow ahead with trying to contact the domain controller to validate your password, but the wireless networking card hasn't found the base station, and you get an error. (Nitpickers should at this point stifle screams of cached credentials. I'm just giving an example. If you don't like this example, go find another one.) I don't know whether it will help or not, but you can try disabling Fast Logon and forcing the system to wait for the network to be fully initialized before allowing logon to occur.

    In the second case, the problem is that the remote desktop service is not yet fully started by the time the program in the Startup group tries to use it. Under such conditions, you may want to query the status of the remote desktop service; if it reports a status of SERVICE_START_PENDING, then the service is starting up but is not yet ready. You need to wait wait until the service status is SERVICE_RUNNING before you can start using the remote desktop service.

    Anyway, the point for today is that Autologon itself doesn't have problems. Rather, Autologon takes away the "seconds of rest" the computer normally experiences while it's waiting for a human being to log in, and sometimes it's those extra few seconds that you were inadvertently relying upon.

  • The Old New Thing

    Fixups are not the same as rewriting code, they're just fixups

    • 18 Comments

    Classically speaking, a linker cannot rewrite the code the compiler generated; its job is merely to resolve symbols. Of course, resolving symbols means that references to those symbols in the code generated by the compiler turn from "I don't know" to "Here it is." Somebody named George appeared to be confused by this, believing that all changes by the linker counted as "rewriting code."

    Obviously if the linker weren't allowed to change anything at all, there wouldn't be much point to having a linker. For example, you wouldn't be able to access functions or variables in a separate compilation unit (for example, from a library) because the compiler doesn't know what the final address is; that's what the linker is supposed to figure out. (Indeed, if function-level linking is enabled, then even calls within a compilation unit are left as insert address here.) The linker resolves symbols and patches up code references that used to say insert address here so that they contain the actual address.

    I think George took my statement a bit too literally. The linker can't change a direct call to an indirect call; that's not something that the compiler told the linker how to do. All the linker can do is patch up insert address here fixups. It can't say "Oh, I'm going to take your two mov instructions and reverse the destination registers, and then flip the arguments to the subsequent sub instruction." (I'm talking about classical linking; the introduction of link-time code generation further blurs the line between the compiler and the linker.)

    George also made the common mistake not only of calling this Web site a "document from MSDN" but also applying the same description to a Microsoft Systems Journal article from 1997. The back issues of MSJ are included in MSDN as a courtesy. Neither the back issues nor the contents of this Web site are under MSDN editorial control.

  • The Old New Thing

    How do I disable Windows 8 touch contact visualizations for my application?

    • 13 Comments

    You might have an application (like a game) where the default touch contact visualizations are a distraction. In WinRT, you can disable the contact visualizations by simply saying

    // JavaScript
    Windows.UI.Input.PointerVisualizationSettings.
        getForCurrentView().
        isContactFeedbackEnabled = false;
    
    // C#
    Windows.UI.Input.PointerVisualizationSettings.
        GetForCurrentView().
        IsContactFeedbackEnabled = false;
    
    // C++
    Windows::UI::Input::PointerVisualizationSettings::
        GetForCurrentView()->
        IsContactFeedbackEnabled = false;
    

    In Win32, you use the Set­Window­Feedback­Setting function. To demonstrate that, let's take our scratch program and make this simple change:

    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
     BOOL fEnabled = FALSE;
     SetWindowFeedbackSetting(hwnd,
        FEEDBACK_TOUCH_CONTACTVISUALIZATION,
        0, sizeof(fEnabled), &fEnabled);
     return TRUE;
    }
    

    The touch visualizations are white and the default window color is white, so the visualizations are hard to see in the scratch program. Let's change the color to something that the visualizations will be more visible against.

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

    Run the program, and you'll see that if you touch the window and drag your finger around, there is no little white circle and no white streak that follows your finger. (Note, however, that the Optimize visual feedback for projection to an external monitor, setting overrides the FEEDBACK_TOUCH_CONTACT­VISUALIZATION setting, so if you have projection contacts enabled, then you still get the dark circles. Another way to get dark circles is to stay up late and not get enough sleep.)

    Although we disabled contact visualizations, we still get visualizations for gestures like tap or tap-and-hold. We can turn those off, too:

    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
     BOOL fEnabled = FALSE;
     SetWindowFeedbackSetting(hwnd,
        FEEDBACK_TOUCH_CONTACTVISUALIZATION,
        0, sizeof(fEnabled), &fEnabled);
     SetWindowFeedbackSetting(hwnd,
        FEEDBACK_TOUCH_TAP,
        0, sizeof(fEnabled), &fEnabled);
     SetWindowFeedbackSetting(hwnd,
        FEEDBACK_TOUCH_DOUBLETAP,
        0, sizeof(fEnabled), &fEnabled);
     SetWindowFeedbackSetting(hwnd,
        FEEDBACK_TOUCH_PRESSANDHOLD,
        0, sizeof(fEnabled), &fEnabled);
     SetWindowFeedbackSetting(hwnd,
        FEEDBACK_TOUCH_RIGHTTAP,
        0, sizeof(fEnabled), &fEnabled);
     return TRUE;
    }
    

    The complete list of things you can disable is given by the FEEDBACK_TYPE enumeration.

  • The Old New Thing

    When should I use the FIND_FIRST_EX_LARGE_FETCH flag to FindFirstFileEx?

    • 14 Comments

    Windows 7 introduces a new flag to the Find­First­File­Ex function called FIND_FIRST_EX_LARGE_FETCH. The documentation says that it "uses a larger buffer for directory queries, which can increase performance of the find operation." This is classic MSDN-style normative documentation: It provides "just the facts". Far be it for MSDN to tell you how to write your application; the job of function-level documentation is to document the function. If you want advice, go see a therapist.

    If the reason why you're calling Find­First­File­Ex is to enumerate through the entire directory and look at every entry, then a large buffer is a good thing because it reduces the number of round trips to the underlying medium. If the underlying medium is a network drive halfway around the world, the latency will be high, and reducing the number of calls reduces the overall cost of communication. Another case where you have high latency is if you are enumerating from an optical drive, since those tend to be slow to cough up data, and once you get the medium spinning, you want to get all the information you can before the drive spins the medium back down. On the other hand, if your underlying medium has low latency, then there isn't much benefit to using a large buffer, and it can be a detriment if the channel is low bandwidth, because transferring that large buffer will take a long time, which can result in long pauses on your UI thread.

    But what if you aren't enumerating with the purpose of reading the entire contents but rather are going to abandon the enumeration once you get the answer to your question? For example, maybe your function wants to enumerate the directory to see if it contains more than ten files. Once the tenth call to Find­Next­File succeeds, you're going to abandon the enumeration. In this case, a large buffer means that the underlying medium is going to do work that you will end up throwing away.

    Here's the above discussion summarized in a table, since people seem to like tables so much.

    Scenario Use FIND_FIRST_EX_LARGE_FETCH?
    Enumerating entire directory on UI thread No¹
    on background thread Yes
    Abandoning enumeration prematurely No

    ¹Actually, if you're on a UI thread, you should try to avoid any directory enumeration at all.

Page 369 of 455 (4,547 items) «367368369370371»