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

    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

    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

    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

    What's the difference between LastWriteTime and ChangeTime in FILE_BASIC_INFO?


    The FILE_BASIC_INFO structure contains a number of fields which record the last time a particular action occurred. Two of the fields seem to describe the same thing.


    The time the file was last written to.


    The time the file was changed.

    What's the difference between writing to a file and changing it?

    I'm told that the difference is metadata. The Last­Write­Time covers writes to the file's data stream (which you accomplish via the Write­File function). On the other hand, the Change­Time also includes changes to the file metadata, such as changing its file attributes (hidden, read-only, etc.) or renaming the file.

    (And don't forget that Last­Access­Time updates are off by default now.)

  • The Old New Thing

    To enable and disable a window, use the EnableWindow function


    Commenter Chris 'Xenon' Hanson points out that fiddling with the WS_DISABLED style directly via Set­Window­Long leads to strange behavior. However it isn't the case that "most widget classes work fine." Reaching in and fiddling the style bit directly is like reaching into a program's internal variables and just changing the values: All the other work that is associated with changing the value simply doesn't happen.

    It's like taking a book you checked out of the library, re-shelving it, and then going into the library computer and marking it as "returned". The bookkeeping will say that the book has been returned, but all the other processes associated with a book return has not taken place: People who had placed a hold on the book aren't notified. The "number of books checked out" counter isn't updated. (Which gets interesting when you come to the end of your senior year and the system won't let you graduate because its records say that you still have 1 book outstanding, yet when you say "Show me all the books I have checked out" it returns no records.)

    In the case of windows, merely setting the WS_DISABLED style does not generate WM_ENABLE messages, it doesn't generate accessibility notifications, it doesn't do focus bookkeeping, all it does is set the flag and goes home. Eventually, some code will stop working because something "impossible" happened (in this case, a window transitioning from enabled to disabled without ever receiving a WM_ENABLE message).

    Similarly, the way to change a window's visible state is to use the Show­Window function and not to manipulate the WS_VISIBLE style directly.

    "I think I filed a suggestion on MSDN2.microsoft.com's suggestion box to advise people not to fiddle with the WS_DISABLED flag at runtime via Set­Window­Long() since it seems like a viable route if you don't know otherwise."

    Actually, the advice already exists right at the top of the Window Styles page where it says "After the control has been created, these styles cannot be modified, except as noted." And for WS_DISABLED, it says "To change this after a window has been created, use Enable­Window."

Page 1 of 3 (28 items) 123