• The Old New Thing

    Is there any vendor bias in the way the Start menu determines which programs are most frequently used?


    Chrissy wants to know if there is a bias towards Microsoft products in the selection of most frequently used programs on the Start menu.

    The only bias is in the initial default MFU list, the one that appears upon a fresh login. In Windows XP, the default Start menu MFU contains six slots. The first three point to Windows applications, and the second three point to programs chosen by the OEM. (If the OEM chooses not to take advantage of this feature, or if this is a boxed version of the product, then the second three slots also point to Windows applications.) Which specific three (or six) programs get displayed depend on the system configuration, so it's not like there's a single initial Start menu that applies to everyone.

    Once those initial MFU items are selected, the Start menu algorithm proceeds in a vendor-blind manner. (Indeed, it doesn't even know who the vendor is; no part of the algorithm looks at file version information.)

    The precise algorithm that is used for determining which programs go on the MFU over time has been reviewed by government-appointed regulators, who have not raised any concerns over vendor bias.

    So I hate to say it, Chrissy, but I think it's all in your head.

  • The Old New Thing

    What is the default cursor for a thread?


    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);
            while (GetMessage(&msg, NULL, 0, 0)) {

    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

    Isn't there a race condition in GetFileVersionInfoSize?


    In response to my explanation of what the lpdwHandle parameter in Get­File­Version­Info­Size is used for, Steve Nuchia wonders if there's a race condition between the time you get the size and the time you ask for the data.

    Yes, there is a race condition, but calling the function in a loop won't help because the Get­File­Version­Info function does not report that the buffer is too small to hold all the version data. It just fills the buffer as much as it can and truncates the rest.

    In practice, this is not a problem because you are usually getting the versions of files that you expect to be stable. For example, you might be obtaining the version resources of the files your application is using in order to show them in diagnostics. The file can't change because you're preventing them from changing by using them. In the case that the file changes out from under you, then yes, you will sometimes get partial data.

    While I'm on the subject of Get­File­Version­Info, I figured I'd mention that there's a good amount of code in Ver­Query­Value to handle the following scenario:

    • On Windows NT 3.1, a program calls Get­File­Version­Info to obtain a file version information block.
    • The program writes the information block to a file.
    • The file is preserved in amber for millions of years.
    • A curious scientists discovers the file version information block, loads it from the file back into memory, and calls Ver­Query­Value.

    The modern implementation of Ver­Query­Value still understands the file version information block created by all previous versions of Windows, and if you hand it one of those frozen-in-amber information blocks, it still knows how to extract information from it. It may not be able to do as good a job due to the lack of appropriate buffer space, but it does at least as well as the version of Windows the file version information block was originally generated from. I have no idea whether anybody actually takes advantage of this behavior, but since persisting the file version information block was never explicitly disallowed in the documentation, one could argue that doing so was legal, and the code therefore needs to be ready for it. (Heck, even if it were explicitly disallowed, there would still be a good chance that there's somebody who's doing it.)

    What Ver­Query­Value doesn't handle is people who hand it a file version information block that never came from Get­File­Version­Info in the first place.

  • The Old New Thing

    Why doesn't the MoveWindow function generate the WM_GETMINMAXINFO message?


    Commenter Phil Quirk asks why calling MoveWindow does not result in a WM_GETMINMAXINFO message being sent to validate the moved window size.

    Well, because you moved it after all. You're being trusted to respect your own rules. After all, if you didn't want the window to be wider than 200 pixels, you shouldn't have passed nWidth=300, right?

    The WM_GETMINMAXINFO message is for obtaining minimum and maximum sizing information when the sizes were chosen by a means outside the application's control, such as when you said "I'll let you choose the window size (CW_USEDEFAULT)" or when the user grabbed the corner of the window and started dragging it around. But if you yourself changed the window size, then the window manager assumes that you know what you're doing.

    If you don't trust yourself to follow your own rules, you can intercept the attempt to change the window size by handling the WM_WINDOWPOSCHANGING message.

  • The Old New Thing

    What does it mean when GetQueuedCompletionStatus return ERROR_SEM_TIMEOUT?


    A customer asked for assistance interpreting a failure of the Get­Queued­Completion­Status function.

    We are observing that Get­Queued­Completion­Status is intermittently behaving as follows:

    • The handle is a SOCKET.
    • The function returns FALSE.
    • lpOverlapped != NULL.
    • Get­Last­Error reports ERROR_SEM_TIMEOUT: "The semaphore timeout period has expired."

    That's all the information we have in our log files. We don't know the value of number­Of­Bytes or completion­Key, sorry.

    We realize that this is a rather vague question, but when this problem hits our machines, it causes our internal logic to go into a reset state since it doesn't know what the error means or how to recover. Resetting is expensive, and we would prefer to handle this error in a less drastic manner, if only we knew what it meant.

    The error code ERROR_SEM_TIMEOUT is a rather bad translation of the underlying status code STATUS_IO_TIMEOUT, which is much more meaningful. It means that the I/O operation timed out.

    Colleagues of mine from the networking team chimed in with additional information:

    A common source of this error with TCP sockets is that the maximum retransmission count and timeout have been reached on a bad (or broken) link.

    If you know that the handle is a socket, then you can use WSA­Get­Overlapped­Result on the lpOverlapped that got returned. Winsock will convert the status code to something more Winsocky. In this case, it would have given you WSA­ETIMED­OUT, which makes it clearer what happened.

  • The Old New Thing

    Why does the MoveWindow function let you suppress repainting?


    Commenter Phil Quirk asks via the suggestion box why the MoveWindow function lets you suppress repainting. "Shouldn't the OS be able to figure out if the window needs to be repainted?"

    Indeed the window manager does do a very nice job of figuring it out if you pass bRepaint = TRUE, which is the expected value of the parameter. But if you think you're smarter than the window manager, then you can pass bRepaint = FALSE and tell the window manager, "Even though you think the window needs to be repainted, don't repaint it. Trust me on this."

    Why would you try to outwit the window manager? Maybe you have special knowledge about how your application behaves. For example, you might exploit special properties about the source and destination coordinates and decide that certain portions of the window should not be redrawn but rather should be shared between the old and new locations, sort of like the advanced tricks you can play with the WM_NCCALCSIZE message. Or you might know that your program is going to invalidate the entire client rectangle soon anyway, so a repaint immediately after the move would just be a waste of time. The bRepaint parameter provides an escape hatch, a throwback to the days when the window manager let you do strange things because you might be doing them as part of a clever thing.

    Mind you, these are pretty advanced concerns and most of the time you would be best off just passing bRepaint = TRUE and letting the window manager do its job of deciding what needs to be repainted.

  • The Old New Thing

    Why waste your money on the car when it's the sound system you care about?


    There is apparently a subculture of people who decide to economize on the car part of the "loud stereo in car" formula (since they really don't care about the car—it's all about the music) and put their loud stereo on the back of a bicycle instead.

    This quotation from the article caught my attention:

    "People say, 'It's the next best thing to having a system in a car.' But it's better because you don't even have to roll down the windows."

    I had been unsure what to think about people who drive down the street with their stereos blaring. Are they audiophiles who prefer their music loud? Or are they jerks who like to annoy other people with loud music? That quotation sort of settles it.

  • The Old New Thing

    Can an x64 function repurpose parameter home space as general scratch space?


    We saw some time ago that the x64 calling convention in Windows reserves space for the register parameters on the stack, in case the called function wants to spill them. But can the called function use the memory for other purposes, too?

    You sort of already know the answer to this question. Consider this function:

    void testfunction(int a)
     a = 42;

    How would a naïve compiler generate code for this function?

        sub rsp, 8 ;; realign the stack
        ;; spill all register parameters into home locations
        mov [rsp+0x10], rcx
        mov [rsp+0x18], rdx
        mov [rsp+0x20], r8
        mov [rsp+0x28], r9
        ;; a = 42
        mov [rsp+0x10], 42
        ;; return
        add rsp, 8 ;; clean up local frame

    Observe that after spilling the register parameters into their home locations onto the stack, the function modified the local variable, which updated the value in the home location.

    Since a function can arbitrarily modify a parameter, you can see that a function is therefore allowed to arbitrarily modify a parameter's home location. At which point you can see that an optimizing compiler might choose an arbitrary value completely unrelated to the parameter.

    Our test function has only one parameter. What about the other three home registers?

    The caller is responsible for allocating space for parameters to the callee, and must always allocate sufficient space for the 4 register parameters, even if the callee doesn't have that many parameters.

    A function can therefore treat those 32 bytes as bonus free play. The rationale behind those 32 bytes is that it gives you a place to spill your inbound register parameters so that they will be adjacent to the stack-based parameters. (We saw how the naïve compiler took advantage of this by not trying to be clever in its function prologue and simply spilling all register parameters whether it needs them or not.)

    Nevertheless, you are free to use them for whatever purpose you like, and if you're looking at heavily-optimized code, you'll probably find that the compiler found all sorts of clever things it can do with them. For example, a common trick is to use them to save the nonvolatile registers that the function locally uses to hold the corresponding parameter!

    (Did this article look familiar? Turns out I covered this article a few years ago, but I'm senile and accidentally repeated a topic. And since I put so much effort into writing it, I'm going to make you suffer through it, even though it's a repeat. Hey, television programs repeat during the summer.)

  • The Old New Thing

    Why was HDS_FILTERBAR added to the common controls if nobody uses it?


    Mike Dunn was curious about the intended purpose of HDS_FILTERBAR.

    The HDS_FILTERBAR style adds a row below the header control consisting of an edit control and a funnel icon. The funnel icon presumably represents a coffee filter, because after all, everybody in the world drinks coffee as much as people in Seattle. (Developers think they're so clever.)

    Mike points out that new features of the common controls were nearly always used by whatever version of Windows or Internet Explorer shipped that new version. The HDS_FILTERBAR style is a notable exception. What happened?

    I believe the HDS_FILTERBAR feature was originally intended for use by Active Directory; my guess is that dialogs like Find Computer would have taken advantage of it. For whatever reason, that feature was cut from Active Directory, which is why you didn't see anybody using it. However, the feature was cut after the code for the feature was already written and checked into the common controls under the style HDS_FILTERBAR.

    The Active Directory team either forgot to tell the Common Controls team, "Hey, you know that feature we asked you to write for us? Yeah, we don't need it after all," or they did, and the Common Controls team said, "Well, we already wrote it, and we don't want to take the risk that removing it won't introduce a bug, so we'll just leave it in. Maybe somebody else can find a use for it."

    The result was a feature in the header control that nobody used. And since nobody used it, I wouldn't be surprised if it's a little buggy. (We already know that it's more than little ugly.)

  • The Old New Thing

    For Honor, For Excellence, For Pizza


    Hacker News member citizenlow recalls the time I went over after hours to help out the Money team debug a nasty kernel issue. They were running into mysterious crashes during their stress testing and asked for my help in debugging it.

    I helped out other teams quite a bit, like writing a new version of Dr. Watson for the Windows 98 team or writing a new version of the MSConfig tool based on a sketch on a bar napkin. And for a time, I followed the official policy for moonlighting to make sure everybody understood that I was doing work outside the boundaries of my official job duties.

    When the Money folks asked me for help, I told them that before I could help them, they would have to help me fill out some paperwork.

    • Who will you be working for? Microsoft Corporation.
    • Where will you be doing the work? Office XX/YYYY on Microsoft Redmond Campus.
    • When will the work begin and end? Begin on YYYY/MM/DD at 5pm, ending YYYY/MM/DD at 11pm.
    • How much will you be paid for this work?

    The Money folks were not sure how to answer that last question, since they didn't have any formal budget or procedures for hiring an outside consultant, much less any procedures for hiring one from inside the company.

    I told them, "Just write One slice of pizza."

    Nobody from the Personnel department seemed to notice the odd circumstances of this moonlighting request; they simply rubber-stamped it and put it in my file.

    The crash, it turns out, was in Windows itself. There was a bug in the special compiler the Languages team produced to help build certain components of Windows 95 which resulted in an incorrect address computation under a particularly convoluted boundary condition. The Money folks had merely stumbled across this bug as part of their regular testing. I notified the appropriate people, and the Windows team applied a workaround in their code to tickle the compiler into generating the correct code.

    As I recall, the pizza was just fine. It was just your average delivery pizza, nothing gourmet or anything. Not that it had to be, because I wasn't there for the pizza.

Page 378 of 464 (4,637 items) «376377378379380»