June, 2011

  • The Old New Thing

    2011 mid-year link clearance

    • 18 Comments

    Another round of the semi-annual link clearance.

    And, as always, the obligatory plug for my column in TechNet Magazine:

  • The Old New Thing

    The UseUrl attribute in the App Paths key indicates that your application can accept a URL on the command line

    • 6 Comments

    Setting the UseUrl attribute in your App Paths key indicates that your application can accept a URL on the command line as the document to be opened. The documentation for this attribute is a confusing blend of raw documentation, guidance, history, and an example. Let's tease the parts apart so you won't confuse the example with the contract.

    The raw documentation is simple: Setting UseUrl indicates that your application can accept URLs on the command line.

    The guidance is that programs like Web browsers should set this attribute because opening URLs is the primary reason for their existence. But it's not just Web browsers; any program which can open documents directly from the Internet can set this attribute. Another category of programs that often falls into this category is media players, since it is common for media players to play content directly from a URL as well as playing content from a file.

    The example given in the documentation of a component which uses this attributes is Web Folders: If you are browsing a WebDAV folder and right-click on a file stored on the Web server, the Open command will be made available if the application registered to handle the file marks itself as UseUrl. If not, then the user will have to download the file and open the downloaded copy.

    The history is that this attribute was invented by the Web Folders team, and for a long time, they were the only component which used it. The UseUrl attribute went under-documented for a long time because the shell documentation team didn't know that this attribute existed. The Web folders team simply made it up and didn't tell the shell team that they were extending a shell feature.

    The Internet Explorer team discovered this "feature from another planet" when they went about implementing the "Edit" button in their toolbar and wondered why some HTML editors worked and others didn't. The shell team also discovered this feature and retroactively added support for it in a few places, such as in the Shell­Execute function if you try to open a document via URL. If the handler is not marked as UseUrl, the Shell­Execute function will download the document to a local file and invoke the handler on the local copy.

  • The Old New Thing

    What happens to WPARAM, LPARAM, and LRESULT when they travel between 32-bit and 64-bit windows?

    • 6 Comments

    The integral types WPARAM, LPARAM, and LRESULT are 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems. What happens when a 32-bit process sends a message to a 64-bit window or vice versa?

    There's really only one choice when converting a 64-bit value to a 32-bit value: Truncation. When a 64-bit process sends a message to a 32-bit window, the 64-bit WPARAM and LPARAM values are truncated to 32 bits. Similarly, when a 64-bit window returns an LRESULT back to a 32-bit sender, the value is truncated.

    But converting a 32-bit value to a 64-bit value introduces a choice: Do you zero-extend or sign-extend?

    The answer is obvious if you remember the history of WPARAM, LPARAM, and LRESULT, or if you just look at the header file.

    The WPARAM is zero-extended, while LPARAM and LRESULT are sign-extended.

    If you remember that WPARAM used to be a WORD and LPARAM and LRESULT used to be LONG, then this follows from the fact that WORD is an unsigned type (therefore zero-extended) and LONG is a signed type (therefore sign-extended).

    Even if you didn't know that, you could look it up in the header file.

    typedef UINT_PTR WPARAM;
    typedef LONG_PTR LPARAM;
    typedef LONG_PTR LRESULT;
    

    UINT_PTR is an unsigned type (therefore zero-extended) and LONG_PTR is a signed type (therefore sign-extended).

  • The Old New Thing

    A different way to win from one of those claw game

    • 22 Comments

    I know two people (siblings) who are experts at those claw games. They can look at a claw game, assess the situation, decide whether there is a winnable toy, and if so, drop in their quarter and grab it. I asked the elder sibling how they arrived at this amazing skill.

    "As a teenager, I spent something like $20 pumping quarters into one of these machines, and I eventually figured it out."

    Or there is the direct approach.

  • The Old New Thing

    How do I display the Find Printers dialog programmatically?

    • 6 Comments

    A customer wanted to display the Find Printers dialog programmatically to let the user pick a printer from Active Directory and wanted to know whether this was possible.

    Yes, it's possible, and there's more than one way to do it. There's the lazy way and the overachieving way.

    The overachieving way is to use the ICommon­Query::Open­Query­Window method. The Find­AD­Printers sample function spells it all out for you.

    The lazy way takes a little bit of out-of-the-box thinking: Open the Find Printers dialog, set up the search the way you want it, and then save the search to a file (File, Save Search). In your program, when you need to open the Find Printers dialog, just Shell­Execute the saved search.

  • The Old New Thing

    There's more to workflow than hitting F5 in the IDE

    • 10 Comments

    Commenter Stu suggested that instead of having code to auto-correct dialog templates, why not have a program that corrects them at build time? That way, Windows wouldn't have to make all these accommodations for programs that didn't understand the new dialog template requirements for property sheet pages.

    For one thing, this model assumes that all dialog templates come from Win32 PE resources and aren't generated at runtime or loaded from other files not in resource format. For those cases, you still need the runtime fixup, so this solution would be a supplement to the existing one rather than a replacement.

    Even if you cover your ears and pretend that all dialog templates come from Win32 PE resources, you still have a problem. Certainly such a program could have been written, and people could have added it to their project as a postbuild step (Fix­Property­Sheet­Templates.exe $(Output.Directory)\myapp.exe), and if you really want to, you can write this program yourself and add it to your build process. But you're also assuming that this is the entire workflow.

    After the myapp.exe program is built, you have to hand the program off to your translation team for them to translate all the resources, and the translation program they use crashes or otherwise rejects these "corrupted" dialog templates. Now you have to change your workflow so you save the original "broken" version of myapp.exe and give that to your translation team, then have to remember to re-fix it when they return it. If your existing workflow consisted of the translation team handing the translated program directly to your QA team, well now you have to insert another step into the workflow where the binary comes back to the development team so it can have its final touch-up applied before being sent back out.

    Sure, you could manage this too, but after you deal with all of these tiny issues, you find yourself with a dozen additional tiny issues to deal with, and then you'd just wish that the fix was made in the operating system to save everybody on the planet all this hassle.

    (And then later you discover that when you load myapp.exe into your IDE, it reports that the dialog templates are corrupted and refuses to let you see them. Now you need a Damage­Property­Sheet­Templates.exe program to undo the fix!)

  • The Old New Thing

    Why doesn't my MessageBox wrap at the right location?

    • 44 Comments

    A customer reported that the MessageBox function was wrapping text "at the wrong location."

    Our program displays a message with the MessageBox function, and we use the '\n' character to force line breaks at positions we choose. But we've found that starting in Windows Vista, the line breaks we placed are not working. The MessageBox function is inserting its own line breaks, which interferes with our custom text layout. It used to be that the width of the message box would expand to fit the longest line in the message.

    The MessageBox function is one of those "leave the driving to us" type of functions. You give it a string to display, select which buttons you want, and sit back and relax while the MessageBox function does the work. The trade-off for the simplicity is that you also lose control over the experience. The MessageBox function decides where to place the dialog and how big to make it, which in turn determines where the line breaks go.

    The algorithm used by MessageBox to determine the size of the message box has changed many times over the lifetime of Windows. In Windows 3.1, it was the width of the longest line, or 5/8 of the width of the screen, whichever was smaller. Windows 95 chose the smallest of the following which resulted in a dialog box that fit inside the working area:

    • the width of the longest line,
    • 5/8 of the width of the working area,
    • 3/4 of the width of the working area,
    • 7/8 of the width of the working area,

    Notice that even in Windows XP, the dialog box was not guaranteed to be the width of the longest line. If the longest line was more than 5/8 of the width of the working area, the MessageBox is probably going to insert its own line breaks beyond ones you inserted explicitly.

    Windows Vista changed the algorithm again, in recognition of two things. First, monitors are now much larger than they were in 1995. And second, the consequence of these larger monitors is that the 7/8 rule resulted in message boxes that were unreadable because they were 10 inches wide and half an inch tall. The old algorithm did not age well, but then again, it was written back in the days when the really cool kids had 1024×768 screens. Nowadays, even the kids from the wrong side of the tracks have screens that are regularly 1400 or even 1600 pixels wide.

    The new algorithm merely adds another option to the table of choices:

    • the width of the longest line,
    • 278 DLU,
    • 5/8 of the width of the working area,
    • 3/4 of the width of the working area,
    • 7/8 of the width of the working area,

    Note that the details of the MessageBox line breaking algorithm are provided for historical purposes only. Do not write code which relies on them, because who knows, they may change again in the next version of Windows.

    The algorithm was changed at the request of the visual design team; after all, it's the job of the visual design team to make these sorts of visual design decisions. If you don't want some black-turtleneck-wearing designer in Redmond to decide where your line breaks go, then don't use MessageBox. And you don't have to go and convert every single message box to its own dialog template; just write a function called MessageBoxWithLineBreaksExactlyWhereIPutThem function that takes the same parameters as MessageBox but lays out the text exactly the way you want it. (The DT_CALCRECT flag will be useful here.)

  • The Old New Thing

    What happens when applications try to copy text by sending Ctrl+C

    • 20 Comments

    I'm stealing this story from one of my colleagues.

    I remember one app from a long time ago that had a feature where you could hit a global short cut key (or something like that) to launch the dictionary. It was also smart in that it would detect the current selected text and immediately search the dictionary for that term.

    One day I was running a Perl script that took several hours to run. It was nearly done and for whatever I decided to launch the dictionary. It sent a Ctrl+C to my Perl script and killed it.

    And that's why you don't send Ctrl+C to arbitrary applications.

    Active Accessibility gives you access to the text under the cursor. There's also a newer interface known as UI Automation which has a handy method called IText­Provider::Get­Selection. (On the managed side, you have System.Windows.Automation.Text­Pattern.Get­Selection.)

    Update: Commenter parkrrrr points out the IText­Provider::Get­Selection. is the provider-side interface. The interface for applications wishing to read the selected text is IUI­Automation­Text­Pattern.

  • The Old New Thing

    How do I compress files (via NTFS compression) from the command line?

    • 33 Comments

    A customer wanted to know whether there was a way to compress files and directories (in the sense of NTFS compression) from a script or from the command line. They knew about the Properties dialog, but they wanted something scriptable.

    The command-line tool for this is COMPACT.EXE. Type compact /? for usage information.

    The customer liaison was grateful for this information.

    Thanks for the prompt response, and yes, this will meet our customer's need to compress specific files such as *.docx under a particular directory and all its subdirectories.

    Um, *.docx files are already compressed. Compressing them again gains you nothing.

    Bonus reading: Functions for manipulating documents which follow the Open Package Conventions are available in both managed and unmanaged versions. Check out the Packaging Team Blog for more information, including a comparison of the managed and unmanaged versions.

  • The Old New Thing

    How to get Windows Media Player to single-step a video

    • 37 Comments

    I always forget how to do this, so I'm going to write it down so I can look it up later.

    When a video is playing, right-click the volume control slider and select Enhancements, then Play speed settings. (Actually, it also works if you right-click the speaker icon, the Stop button, the Replay button, or the Shuffle button, but the volume control slider is the biggest target.)

    On the Play speed settings dialog, the single-step controls are at the bottom; they look like triangles.

    Update: There's an even easier way.

Page 1 of 3 (25 items) 123