• The Old New Thing

    TrackMouseEvent tracks mouse events in your window, but only if the events belong to your window

    • 15 Comments

    Greg Williams wonders why Track­Mouse­Event fails to detect mouse hover events when responding to Do­Drag­Drop callbacks. "My suspicion is that Do­Drag­Drop monopolizes the window so that a WM_MOUSEHOVER message is never posted, so it won't end up being useful."

    That's basically it, for the appropriate sense of the word "monopolize."

    The Track­Mouse­Event monitors mouse events that take place in your window and notifies your window when events of interest occur. But this requires that the events actually take place in your window!

    The Do­Drag­Drop function calls Set­Capture so that it can carry out the task of following the mouse anywhere on the screen. Recall that mouse events normally are delivered to the window beneath the mouse, but Set­Capture lets you say, "No, I want all mouse events to go to me for as long as the mouse button is held down. Mine! All mine!" This function is typically called when you are performing some sort of mouse drag operation so that the window can respond to mouse events even after the use has dragged the mouse out of the window. (Which, in many cases, is the only interesting case.)

    That's why Track­Mouse­Event has no effect when you try to use it to detect mouse hovering during a drag/drop operation: The Track­Mouse­Event function is not seeing any mouse events! They're all being stolen by Do­Drag­Drop.

    The unfortunate consequence of this is that if you want to have a special behavior during drag/drop hover, you'll have to detect the hover manually by remembering the mouse position and timestamp and waiting for the appropriate amount of time to elapse without a significant mouse motion.

    Exercise: But wait, since I don't get drag/drop events when the mouse is not inside my window, how can I simulate WM_MOUSELEAVE?

  • The Old New Thing

    ZOMG! This program is using 100% CPU!1! Think of the puppies!!11!!1!1!eleven

    • 98 Comments

    For some reason, people treat a program consuming 100% CPU as if it were unrepentantly running around kicking defenseless (and cute) puppies. Calm down already. I get the impression that people view the CPU usage column in Task Manager not as a diagnostic tool but as a way of counting how many puppies a program kicks per second.

    While a program that consumes 100% CPU continuously (even when putatively idle) might legitimately be viewed as an unrepentant puppy-kicker, a program that consumes 100% CPU in pursuit of actually accomplishing something is hardly scorn-worthy; indeed it should be commended for efficiency!

    Think of it this way: Imagine if your CPU usage never exceed 50%. You just overpaid for your computer; you're only using half of it. A task which could have been done in five minutes now takes ten. Your media player drops some frames out of your DVD playback, but that's okay, because your precious CPU meter never went all the way to the top. (Notice that the CPU meter does not turn red when CPU usage exceeds 80%. There is no "danger zone" here.)

    Consider this comment where somebody described that they want their program to use less CPU but get the job done reasonably quickly. Why do you want it to use less CPU? The statement makes the implicit assumption that using less CPU is more important than getting work done as fast as possible.

    You have a crowd of people at the bank and only ten tellers. If you let all the people into the lobby at once, well, then all the tellers will be busy—you will have 100% teller utilization. These people seem to think it would be better to keep all the customers waiting outside the bank and only let them into the lobby five at a time in order to keep teller utilization at 50%.

    If it were done when 'tis done, then 'twere well / It were done quickly.

    Rip off the band-aid.

    Piss or get off the pot.

    Just do it.

    If you're going to go to the trouble of taking the CPU out of a low-power state, you may as well make full use of it. Otherwise, you're the person who buys a bottle of water, drinks half of it, then throws away the other half "because I'm thinking of the environment and reducing my water consumption." You're making the battery drain for double the usual length of time, halving the laptop's run time because you're trying to "conserve CPU."

    If the task you are interested in is a low priority one, then set your thread priority to below-normal so it only consumes CPU time when there are no foreground tasks demanding CPU.

    If you want your task to complete even when there are other foreground tasks active, then leave your task's priority at the normal level. Yes, this means that it will compete with other foreground tasks for CPU, but you just said that's what you want. If you want it to compete "but not too hard", you can sprinkle some Sleep(0) calls into your code to release your time slice before it naturally expires. If there are other foreground tasks, then you will let them run; if there aren't, then the Sleep will return immediately and your task will continue to run at full speed.

    And cheerfully watch that CPU usage go all the way to 100% while your task is running. Just make sure it drops back to zero when your task is complete. You don't want to be a task which consumes 100% CPU even when there's nothing going on. That'd just be kicking puppies.

    [Raymond is currently away; this message was pre-recorded.]

    Clarification: Many people appear to be missing the point. So let's put it more simply: Suppose you have an algorithm that takes 5 CPU-seconds to complete. Should you use 100% CPU for 5 seconds or 50% CPU for 10 seconds? (Obviously, if you can refine your algorithm so it requires only 2 CPU-seconds, that's even better, but that's unrelated to the issue here.)

  • The Old New Thing

    The alignment declaration specifier is in bytes, not bits

    • 18 Comments

    Explicit object alignment is not something most people worry about when writing code, which means that when you decide to worry about it, you may be a bit rusty on how the declarations work. (After all, if it's something you worried about all the time, then you wouldn't have trouble remembering how to do it!)

    I was looking at some customer code, and there was a class who had a data member with an explicit alignment declaration.

    class Whatever {
        ...
        __declspec(align(32)) LONG m_lSomething; // Must be DWORD-aligned to make writes atomic
        ...
    };
    

    I pointed out that the comment didn't match the code. The comment says that the variable needs to be DWORD-aligned (which in Windows-speak means aligned on a 32-bit boundary), but the code aligns it on a 32-byte boundary, eight times as generous as required. On the other hand, maybe they really did want the member aligned on a 32-byte boundary (say to put it on its own cache line).

    Turns out that in this case, the comment was correct and the code was wrong. To force a variable to align on a DWORD boundary, you want to say __declspec(align(4)). Save yourself a bunch of unnecessary padding bytes.

    But in fact, in this case, the customer was simply trying too hard. The code was compiled with default alignment, which aligns integer types on their natural boundaries anyway. The compiler was going to align the variable even if you didn't specify anything.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    I will be speaking at TechEd China 2010 today

    • 17 Comments

    As I've mentioned a few times by now, the way to get me to show up at your event is to invite me. The easiest (i.e. cheapest) way is to hold your event in the Seattle area so that my travel expenses are effectively zero; I just use my bus pass. The folks at TechEd China 2010, on the other hand, had to fly me all the way out to Beijing, which is where I've been this week.

    Preparing these talks is a lot of work, because each one is different. It's not like I have a "stock presentation" that I give over and over. So even if you invite me, I may decline because I simply don't have the time to write up a new presentation for your event, and if your event is outside the Seattle area, I may decline because the travel would take me away for too long. (The TechEd China folks actually invited me last year, but I already had accepted an out-of-town invitation and couldn't really afford two out-of-town presentations in one year.)

    Anyway, if you can read Chinese, then you can check out the TechEd China 2010 Web site — nobody told me that crossed arms was the official speaker pose of TechEd China 2010 — my speaker biography and the talk description. I can't read Chinese, so I'm trusting the translators to have done a good job.

    I've found that a good way to salvage content that I've deleted from the queue (because the topic draws out flame comments) is to use them in talks and presentations instead. It turns out that the people who actually show up for a talk are much more polite than those who just post snarky comments from their mother's basement. I think the fact that you have to be snarky in person removes the veil of anonymity and makes you more accountable for what you say.

    And since I know you're going to ask:

    • I'm giving the talk in English.
    • I don't know whether the talk is going to be recorded.
    • The talk is being given on December 2, even though this entry is dated December 1. That's because it will already be December 2 in China.

    [Raymond is currently away, but he wrote this entry just now.]

  • The Old New Thing

    How do I delete bytes from the beginning of a file?

    • 29 Comments

    It's easy to append bytes to the end of a file: Just open it for writing, seek to the end, and start writing. It's also easy to delete bytes from the end of a file: Seek to the point where you want the file to be truncated and call SetEndOfFile. But how do you delete bytes from the beginning of a file?

    You can't, but you sort of can, even though you can't.

    The underlying abstract model for storage of file contents is in the form of a chunk of bytes, each indexed by the file offset. The reason appending bytes and truncating bytes is so easy is that doing so doesn't alter the file offsets of any other bytes in the file. If a file has ten bytes and you append one more, the offsets of the first ten bytes stay the same. On the other hand, deleting bytes from the front or middle of a file means that all the bytes that came after the deleted bytes need to "slide down" to close up the space. And there is no "slide down" file system function.

    One reason for the absence of a "slide down" function is that disk storage is typically not byte-granular. Storage on disk is done in units known as sectors, a typical sector size being 512 bytes. And the storage for a file is allocated in units of sectors, which we'll call storage chunks for lack of a better term. For example, a 5000-byte file occupies ten sectors of storage. The first 512 bytes go in sector 0, the next 512 bytes go in sector 1, and so on, until the last 392 bytes go into sector 9, with the last 120 bytes of sector 9 lying unused. (There are exceptions to this general principle, but they are not important to the discussion, so there's no point bringing them up.)

    To append ten bytes to this file, the file system can just store them after the last byte of the existing contents. leaving 110 bytes of unused space instead of 120. Similarly, to truncate those ten bytes back off, the logical file size can be set back to 110, and the extra ten bytes are "forgotten."

    In theory, a file system could support truncating an integral number of storage chunks off the front of the file by updating its internal bookkeeping about file contents without having to move data physically around the disk. But in practice, no popular file system implements this, because, as it turns out, the demand for the feature isn't high enough to warrant the extra complexity. (Remember: Minus 100 points.)

    But what's this "you sort of can" tease? Answer: Sparse files.

    You can use an NTFS sparse file to decommit the storage for the data at the start of the file, effectively "deleting" it. What you've really done is set the bytes to logical zeroes, and if there are any whole storage chunks in that range, they can be decommitted and don't occupy any physical space on the drive. (If somebody tries to read from decommitted storage chunks, they just get zeroes.)

    For example, consider a 1MB file on a disk that uses 64KB storage chunks. If you decide to decommit the first 96KB of the file, the first storage chunk of the file will be returned to the drive's free space, and the first 32KB of the second storage chunk will be set to zero. You've effectively "deleted" the first 96KB of data off the front of the file, but the file offsets haven't changed. The byte at offset 98,304 is still at offset 98,304 and did not move to offset zero.

    Now, a minor addition to the file system would get you that magic "deletion from the front of the file": Associated with each file would be a 64-bit value representing the logical byte zero of the file. For example, after you decommitted the first 96KB of the file above, the logical byte zero would be 98,304, and all file offset calculations on the file would be biased by 98,304 to convert from logical offsets to physical offsets. For example, when you asked to see byte 10, you would actually get byte 98314.

    So why not just do this? The minus 100 points rule applies. There are a lot of details that need to be worked out.

    For example, suppose somebody has opened the file and seeked to file position 102,400. Next, you attempt to delete 98,304 bytes from the front of the file. What happens to that other file pointer? One possibility is that the file pointer offset stays at 102,400, and now it points to the byte that used to be at offset 200,704. This can result in quite a bit of confusion, especially if that file handle was being written to: The program writing to the handle issued two consecutive write operations, and the results ended up 96KB apart! You can imagine the exciting data corruption scenarios that would result from this.

    Okay, well another possibility is that the file pointer offset moves by the number of bytes you deleted from the front of the file, so the file handle that was at 102,400 now shifts to file position 4096. That preserves the consecutive read and consecutive write patterns but it completely messes up another popular pattern:

    off_t oldPos = ftell(fp);
    fseek(fp, newPos, SEEK_SET);
    ... do stuff ...
    fseek(fp, oldPos, SEEK_SET); // restore original position
    

    If bytes are deleted from the front of the file during the do stuff portion of the code, the attempt to restore the original position will restore the wrong original position since it didn't take the deletion into account.

    And this discussion still completely ignores the issue of file locking. If a region of the file has been locked, what happens when you delete bytes from the front of the file?

    If you really like this simulate deleting from the front of the file by decommitting bytes from the front and applying an offset to future file operations technique, you can do it yourself. Just keep track of the magic offset and apply it to all your file operations. And I suspect the fact that you can simulate the operation yourself is a major reason why the feature doesn't exist: Time and effort is better-spent adding features that applications couldn't simulate on their own.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Microspeak: Take-away

    • 22 Comments

    At Microsoft, the take-away is the essential message of a presentation or the conclusion that you are expected to draw from a situation. It is something you are expected to remember when the whole thing is over, a piece of information you take away with you as you leave the room.

    XYZ demo take away (title of a document)

    The preferred intensifier is key, and you probably see it attached to the phrase take-away more often than not. This example comes from a presentation on the results of a user study:

    Results: XYZ Tough to Use
    • ...
    • Key take-away:
      • Migration to XYZ will be difficult
      • Need to show value of using the power of DEF

    In fact, every single slide in this presentation had a bullet point at the bottom called Key take-away. (And, as you may have noticed, the heading is the singular take-away even though multiple take-aways were listed.)

    Another use of the term take-away follows in the same spirit as the "essential message" usage, but the idea of "taking away" is taken literally: A take-away is a small information card that sales and marketing people give to potential customers. Think of it as the business card for a service rather than for a person.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    What were Get/SetMessageExtraInfo ever used for?

    • 17 Comments

    KJK::Hyperion asks, "Could you shed some light on Get/SetMessageExtraInfo? It's almost like nobody on earth used them, ever, and I can't get some sample code."

    Yup, that's about right. Nobody on earth (to within experimental error) ever used them.

    These functions were introduced on July 20, 1990 (I'm looking at the change history right now) at the request of what was then called the Hand-Writing Windows group, which shipped the first version of Windows for Pen Computing in 1992. The idea was that each input event from the custom pen hardware would have this extra information associated with it, and the software that converted pen input into strokes (and ultimately into gestures or characters via handwriting recognition) would use this extra information to guide the conversion process.

    Seeing as Pen Windows died a hasty death, I think it's fairly accurate to say that nobody on earth will admit to having used these functions.

    For those of you fortunate enough never to have been exposed to Pen Windows, here are some random tidbits of information.

    First, applications needed to be modified to support pen input. In particular, edit controls did not accept text input from the pen. You had to replace them with one of the following:

    • Handwriting edit control (hedit). This accepted free form handwriting input.
    • Boxed edit control (bedit). This accepted handwriting input, but you had to write one letter per box. This constraint resulted in much better character recognition.

    Both of these controls were significantly larger than the standard edit control. They needed to be, in order to give enough room for the user to write. This in turned means that you had to edit all your dialog templates and custom window layout to take into account the larger pen-aware controls.

    And just changing your controls wasn't enough. You also had to write extra code to call various character recognition functions to get the user's pen input converted and recognized.

    Here's an artist's conception of what the boxed edit control looked like:

    D o g

    That weird triangle-shaped thingie was, I believe, called the dinky. What did it do? Beats me.

    There are still vestiges of the old Pen Windows product in the GetSystemMetrics function: Check out SM_PENWINDOWS.

    (Note that the old Pen Windows product is unrelated to the current Tablet PC product, even though they both do handwriting recognition.)

    Bonus chatter: The Windows touch team saw their opportunity and commandeered the extra info (perhaps resurrecting the ghost of Pen Windows) and use the extra info to specify the source of the input.

    [Raymond is currently away; this message was pre-recorded.]

  • The Old New Thing

    Watching the game of Telephone play out in five seconds

    • 17 Comments

    Some time ago, I spent the Thanksgiving holiday with my nieces (ages 3 and 5 at the time), and I overheard this conversation between them.

    "Thanksgiving is over."

    Christmas is coming!

    "It's Christmas time!"

    Today is Christmas!

  • The Old New Thing

    The easy way out is to just answer the question: What is the current Explorer window looking at?

    • 17 Comments

    A customer had the following question:

    We have an application which copies and pastes files. Our problem is that we want to paste the files into the folder which corresponds to the currently active Windows Explorer window. Right now, we're using SendKeys.SendWait("^(v)"), but we find this method unsatisfactory because we want to replace Explorer's default file copy engine with our own custom one. Can you provide assistance?

    (And commenter wtroost had no clue why somebody would copy a file by sending window messages to Explorer. Well here you have it.)

    The easy way out is to answer the question: You can enumerate the active Explorer windows and ask each one what folder it is viewing. There's even a script interface for it.

    The hard way out is to understand the customer's problem and see if there's a better solution. The question as phrased suggests that the customer hasn't thought through the entire problem. What if the current window is not an Explorer window, or if it's a window on a virtual folder instead of a file system folder (for example, an FTP site)? Simulating keyboard input (in this case, fake-pressing Ctrl+V) is rarely a good solution to a problem; after all, what if the hotkey for Paste changes based on the user's preferred language? Or what if the Explorer window happens to be in a state where Ctrl+V doesn't paste files into the current folder? (For example, focus might be on the Address Bar.) And the fact that they put contents onto the clipboard means that they are overwriting the previous contents of the clipboard.

    I asked for a little more information about what their application is trying to do.

    This is a file transfer application for computers which are not directly connected to each other, but which are both connected to a common third computer. From the first computer, you run the file transfer application, select some files from the transfer application's interface, and hit Copy. This transfers the files to the common third computer. Then from the second computer, you run the file transfer application and hit Paste, and the program retrieves the files from the common third computer and places them in the folder that you are currently viewing in Windows Explorer.

    Oh, the whole "get the path to the folder that Windows Explorer is viewing" is just a strange way of telling the program where to copy the files. In other words, they were using Windows Explorer as a very expensive cross-process replacement for the SHBrowseForFolder function.

    The recommendation therefore came in two parts:

    1. Instead of hijacking Explorer as a directory-picker, just call SHBrowseForFolder. You can pass the BIF_RETURNONLYFSDIRS flag, and SHBrowseForFolder will automatically filter out anything that is not a file system folder, thereby saving you the trouble of filtering them out yourself.
    2. If you really want to hijack Explorer as a directory-picker, then add a context menu command to Directory or Directory\Background called Paste from Transfer Shelf (or whatever your application calls that intermediate computer).
  • The Old New Thing

    What if two programs did this? Practical exam

    • 41 Comments

    A customer who doesn't read this blog had the following question:

    The requirement for our application is that it must be on top of all other windows, even in the presence of other windows with the topmost style. In our WM_KILLFOCUS and WM_PAINT messages, we set ourselves to topmost, and then call SetWindowPos to bring ourselves to the front, and then we SetForegroundWindow ourselves just to make sure.

    The result is that our application and another application end up fighting back and forth because both applications are applying similar logic to remain on top. There are other applications that defeat our logic, and they manage to cover our application. (These other applications are third party applications we have no control over.)

    We are in the process of writing a DLL to hook all messages for all windows and [even crazier things that aren't worth elaborating on], but at the moment this causes the other hooked applciations to crash. We are also considering setting a timer and calling SetWindowPos when the timer fires, but that seems inefficient.

    The customer didn't even have to run through the thought experiment What if two programs did this?; they got to run it in real life! And the result was as predicted: The two programs fight with each other to be the one that is on top of the other. Nobody wins; everybody loses, especially the user.

Page 125 of 434 (4,332 items) «123124125126127»