July, 2010

  • The Old New Thing

    No, you can't lock a gadget to the top of the sidebar


    In another installment of I bet somebody got a really nice bonus for that feature, I offer you this customer:

    My customer has created a Windows Vista sidebar gadget and wants to know if there's a way to force this gadget to appear at the top of the sidebar and prevent the user from moving or removing it.

    I applaud this company for having written the most awesome sidebar gadget in the history of the universe. It's so compelling that it should override the user's preferences and force itself into the upper right corner of their screen in all perpetuity.

    Unfortunately, Windows was not prepared for a program as awesome as this, and there is no supported way to force a gadget into a particular position and prevent the user from moving or removing it.

  • The Old New Thing

    Suggestion Box 4


    The topic backlog from Suggestion Box 3 has nearly cleared out, and I've actually been enjoying not having to write up a reply every Monday for the past several months, but all good things must come to an end, and so, without much fanfare, we now have Suggestion Box 4.

    Remember, the suggestion box is for suggestions for future topics. It isn't for developer support, bug reports, or ranting. Topics I'm inclined to cover:

    • Windows history (particularly the Windows 95 era).
    • Windows user interface programming in Win32, and shell programming in particular.
    • General programming topics (selectively).
    • Issues of general interest.
    • My personal hobbies.

    Topics I am not inclined to cover:

    • The blog software itself. You can visit the Community Server home page and cruise their support forums.
    • Internet Explorer. You can try the IE folks.
    • Visual Studio. You can try one of the Visual Studio blogs.
    • Managed code. This is not a .NET blog. I do not work on .NET technologies. As far as .NET is concerned, I'm just another programmer like you. Occasionally I touch a .NET-related topic (including the annual "CLR Week"), but I do not bring any inside expertise to the subject.
    • Non-software Microsoft topics, such as product support policies, marketing tactics, jobs and careers, legal issues.
    • Microsoft software that isn't Windows. (Exchange, Office, ...)
    • Windows topics outside user interface programming. (Plug and Play, Terminal Services, Windows Messenger, Outlook Express, SQL, IIS, remoting, SOA...)
    • User interface programming in anything other than Win32. (Because I know nothing about it.)
    • Debugging a specific problem. (Not of general interest.)
    • Predictions for the future. (What's the title of this blog again?)
    • Participation in Internet memes.

    Selected products at Microsoft participate in the Connect program, and many more have official blogs.

    Suggestions should be between two and four sentences in length. Think of it as an elevator pitch: You have three seconds to get your point across. Please also search the Web site first because your suggestion may have already been covered. (Possibly as a suggestion that was submitted to an earlier Suggestion Box that was not accepted.) And remember, questions aren't suggestions.

    The Suggestion Box will be open for only two weeks, and I will be much more selective about which one I choose to accept than in previous go-rounds. I'll answer one every Monday of 2012 (minus holidays and special events such as CLR Week), and once the end of the year is reached, that's the end of Suggestion Box 4.

  • The Old New Thing

    Decoding the parameters of a thrown C++ exception (0xE06D7363)


    Special preview content for my TechReady talk later today. I'd like to claim it was planned this way, but actually it was just a coincidence.

    The Visual C++ compiler uses exception code 0xE06D7363 for C++ exceptions. Here's how you can decode the other parameters. (Handy if you're debugging a crash dump.)

    Note that this information falls under the category of implementation detail. There is no guarantee that this method will continue to work in the future, so don't write code that relies on it. It's just a debugging tip.

    When the C++ exception is raised, the exception code is 0xE06D7363 and there are three (possibly four) parameters.

    • Parameter 0 is some internal value not important to the discussion.
    • Parameter 1 is a pointer to the object being thrown (sort of).
    • Parameter 2 is a pointer to information that describes the object being thrown.
    • Parameter 3 is the HINSTANCE of the DLL that raised the exception. (Present only on 64-bit Windows.)

    The object being thrown is pretty much the object being thrown, except that sometimes there is some junk in front that you have to skip over. Once you figure out what it is, you can dump it. (I haven't bothered trying to figure out exactly how much; I just dump bytes and figure out the correct start of the object by inspection.) But what is it? That's what Parameter 2 tells you, but in a very roundabout way.

    Take Parameter 2 and go to the fourth DWORD and treat it as a pointer. (On 64-bit systems, you have to add this value to the HINSTANCE passed as Parameter 3 to convert it to a pointer.)

    Next, go to the second DWORD and treat it as a pointer. (Again, on 64-bit systems, it's really an offset from the HINSTANCE.)

    Next, go to the second DWORD and treat it as a pointer. (64-bit systems: you know the drill.)

    Finally, skip over the first two void*s and the rest is the class name.

    Here's a picture, rendered in high-tech ASCII line drawing. Pointer-sized fields are marked with an asterisk, and fields whose value are unknown or not important are marked with tildes.

    | E06D7363 |
    |  ~~~     |
    |* ~~~     |
    |* ~~~     |
    | 3 or 4   |
    |* ~~~     |
    |*Object   |
    +----------+     +---+
    |*       ------> |~~~|
    +----------+     +---+
    |*HINSTANCE|     |~~~|
    +----------+     +---+
                     +---+    +---+
                     | -----> |~~~|
                     +---+    +---+    +---+
                              | -----> |~~~|
                              +---+    +---+    +----------+
                                       | -----> |*   ~~~   |
                                       +---+    +----------+
                                                |*   ~~~   |
                                                |Class name|

    "When in doubt, add another level of indirection" appears to be the mantra here.

    Here's a real-world example I had to debug. This came from a crash dump in a third-party application reported via Windows Error Reporting, so all debugging has to be done without source code or symbols.

    0:008> .exr 00000000`015dede0
    ExceptionAddress: 000007fefd23bb5d (KERNEL32!RaiseException+0x39)
       ExceptionCode: e06d7363 (C++ EH exception)
      ExceptionFlags: 00000001
    NumberParameters: 4 // this is running on 64-bit Windows
       Parameter[0]: 0000000019930520
       Parameter[1]: 00000000015def30 // object being thrown
       Parameter[2]: 00000000100cefa8 // magic Parameter 2
       Parameter[3]: 0000000010000000 // HINSTANCE

    According to the cookbook, we follow Parameter 2:

    0:008> dd 00000000100cefa8 l4
    00000000`100cefa8  00000000 00000000 00000000 000cefc8

    and take the fourth DWORD. Since this is a 64-bit machine, we add it to the HINSTANCE before dumping. (If this were a 32-bit machine, we would just dump it directly.)

    0:008> dd 100cefc8 l2
    00000000`100cefc8  00000005 000ceff8

    Now we take the second DWORD (add the HINSTANCE since this is a 64-bit machine) and then dump it again:

    0:008> dd 100ceff8 l2
    00000000`100ceff8  00000001 000d6670

    Okay, we're within striking distance now. Since this is a 64-bit machine, we add the HINSTANCE to the offset. And on all platforms, we add two pointers (which is 0x10 on a 64-bit machine and 8 on a 32-bit machine). The result should be an ASCII string representing the class name:

    0:008> da 100d6670+10
    00000000`100d6680  ".PEAVCResourceException@@"

    If you ignore the decorations, you see that this is telling you that the object thrown was a CResource­Exception.

    And for old time's sake, here's a 32-bit version I just made up now.

    0:000> .exr 0008f2e4
    ExceptionAddress: 7671b046 (kernel32!RaiseException)
       ExceptionCode: e06d7363 (C++ EH exception)
      ExceptionFlags: 00000001
    NumberParameters: 3 // 32-bit platform
       Parameter[0]: 19930520
       Parameter[1]: 0008f384 // object being thrown
       Parameter[2]: 10cfed60 // magic Parameter 2
    0:000> dd 10cfed60 l4
    10cfed60  00000000 00000000 00000000 10db297c
    0:000> dd 10db297c l2
    10db297c  00000004 10db2990
    0:000> dd 10db2990 l2
    10db2990  00000001 10dbccac
    0:000> da 10dbccac+8
    10dbccb4  ".PAVCFileException@@"

    Anyway, back to the original problem: Knowing that the object being thrown was a CResource­Exception was a big help, because that's a class used by MFC, so I have additional information as to what it does and how it's used. This turns out to have been the necessary foothold to identify the source of the problem, which will be the subject of a future write-up.

  • The Old New Thing

    Crackpots in computer security: The neighbors are looking at me weird


    The security team gets all sorts of email to report security issues. Nearly 200,000 each year. And of course the reports vary in quality greatly. The ones I'm fascinated by are the crackpots.

    Importance:  High


    Capitalization is preserved from the original, but identifying information has been deleted.

    It's possible that he's actually onto something. After all, just because you're paranoid doesn't mean they aren't out to get you.

  • The Old New Thing

    Hardware backward compatibility: The firmware that missed one tiny detail


    The person responsible for the floppy disk driver in Windows 95 also was responsible for the low-level CD-ROM drivers. (Not to be confused with the CDFS file system, which was handled by the file system team, not the hardware driver folks.) And I remember a story about one particularly strange CD-ROM drive.

    This drive was produced by a name-brand manufacturer. The box that the drive comes in proudly announces that it is an IDE ATAPI drive. And they did a fantastic job. They implemented all the ATAPI commands that were defined at the time, with one tiny exception.

    They forgot to implement the "Are you an ATAPI drive?" command.

  • The Old New Thing

    Things I've written that have amused other people, Episode 7


    A customer asked for advice on how to accomplish something, the details of which are not important, except to say that what they were trying to do was far more complicated than the twenty-word summary would suggest. And I wasn't convinced that it was a good idea, sort of like asking for advice on how to catch a baseball in your teeth or pick all the cheese off your cheeseburger.

    I explained several of the pitfalls of their approach, the ones that I could think of off the top of my head, things they need to watch out for or take precautions against, and I concluded with the sentence, "This idea is fraught with peril, and I fear that my answers to your questions will be interpreted as approval rather than reluctant assistance."

    That sentence immediately went into many people's Raymond-quotes file.

  • The Old New Thing

    Hardware backward compatibility: The finicky floppy drive


    I think the behavior is more petulant than finicky, but finicky is alliterative.

    Back in the days of Windows 95, I was talking with the person responsible for, among other things, the floppy disk driver, and I learned about a particular driver hack that was needed to work around a flaw in a very common motherboard chipset.

    Apparently the floppy disk controller in this chipset was very picky about how you talked to it. If the very first command it receives after power-on is a read request, and there is no disk in the drive, the controller chip hangs unrecoverably. Issuing a reset to the chip has no effect. It's gone. You have to power-cycle the machine and try again.

  • The Old New Thing

    How do I configure a Remote Desktop Connection shortcut to open on a specific monitor?


    A customer wanted to know how to configure a Remote Desktop Connection shortcut so that the session appears on the monitor of choice. "I have two RDP shortcuts, and each one displays on a different monitor, but I want them all to display on my 20-inch monitor. How do I tell the bad shortcut, 'Hey, use that monitor over there please'?"

    Normal shell shortcuts (LNK files) do not encode monitor information. It is up to the application to decide where to display its windows. Many applications save the window position when you exit and restore it when you restart. If you have one of these types of programs, then the solution is simple: Move the window to where you want its position to be remembered, and then close it.

    In the case of RDP files, the window position is stored in the RDP file settings. The Terminal Services Team Blog tells you how.

    One thing I found interesting about that blog entry is that none of the comments is on topic. Well, okay maybe two of them.

  • The Old New Thing

    Tips for planning your ship party


    Not saying how I know these things. Just making a little list for reference.

    • If you plan on staying dry, do not hold the party near a fountain. (Note that fountain avoidance is a necessary but not sufficient criterion.)
    • Corollary: If your team members have an armory of super soaker water cannons, and you plan on staying dry, then absolutely do not hold the party near a fountain.
    • Unrolled spools of bubble wrap are a poor choice of equipment when trying to climb from the lobby to the upper floor balcony.
    • After discovering that bubble wrap is unsuitable for climbing, do not upend a glass table in an attempt to gain a higher starting point.
    • A contest to see who can run and break through a plaster wall is not a recommended choice of impromptu amusement.
    • Do not throw a couch from the upper floor balcony. Not even if it's on fire.
    • Costco underwear does not count as swim trunks.
    • Do not have a tug of war over a vat of Jell-O.
    • The expensive sculpture outside your building is not a water storage tank in need of refilling.
    • Exercise caution when driving your motorcycle through the halls. The carpet damage from your burnout can be repaired, but the patches never really look the same.
    • On the day of the ship party, do not wear a nice suit. You might be thrown into the back of a pick-up truck and buried in ice.

    Bonus: Other lessons learned.

  • The Old New Thing

    Why didn't Windows XP auto-elevate programs beyond those named setup.exe?


    Commenter J-F has a friend who wonders why Windows XP didn't auto-elevate all installers but rather only the ones named setup.exe. (Perhaps that friend's name is Josh, who repeated the question twelve days later.)

    Remember what the starting point was. In Windows 2000, nothing was auto-elevated.

    Before adding a feature, you have to know what problem the feature is trying to solve. The problem is improving the experience for non-administrators who want to install software. When they try to install a program and forget to use the Run as feature, then instead of proceeding halfway through the installer and then getting an Access denied error, do the Run as for them automatically.

    Knowing whether the user is running an installer that requires elevation requires a degree of semantic analysis beyond what you want to add to the Create­Process code path. Hey, here's a program called PRONT4.EXE. Is it an installer? Turns out that it is. And then there are the programs that might be installers, depending on what other command line switches you provide.

    Given that you're reduced to a heuristic, you have to decide what the acceptable rates of false positives and false negatives will be. If you guess wrong and think a program requires administrator privileges when it doesn't, then you've screwed over all the non-administrators who want to use the program. "I used to be able to run this program, but now when I try, I'm asked for the administrator password, which I do not know. Windows broke my program." The effect of a false positive is My program stops working.

    On the other hand, if you fail to detect a program that requires being run with administrator privileges, the behavior is the same as before: The user gets an Access denied error. The effect of a false negative is No change.

    Given that the cost of a false positive is huge and the cost of a false negative is zero, you can see that the math says to use a conservative heuristic. The heuristic is that a program named setup.exe will be treated as an installation program, and nothing else.

    Windows was under no obligation to auto-detect installation programs. Indeed, according to the strict interpretation of operating system design, it shouldn't do this. If the user says to run this program at the current privilege level, then you darned well better run the program with the current privilege level. The treatment of programs named setup.exe is really just a compatibility hack, a courtesy to make your life a little bit easier.

    It's a case of giving somebody five dollars and being asked why you didn't give them ten.

    Starting in Windows Vista, applications can specify via a manifest whether they want to run at the privilege level the user requested (requested­Execution­Level level="as­Invoker") or always to elevate to administrator (requestedExecution­Level level="require­Administrator"). Hopefully, all new applications will specify their elevation requirements explicitly, and the heuristic will be necessary only for old programs.

Page 1 of 3 (28 items) 123