January, 2009

  • The Old New Thing

    Why do I get the error REGDB_E_IIDNOTREG when I call a method that returns an interface?


    This is another manifestation of the missing marshaller problem.

    IContextMenu *pcm;
    HRESULT hr = psf->GetUIObjectOf(hwnd, 1, &pidl,
                   IID_IContextMenu, NULL, &pcm);
    // fails with REGDB_E_IIDNOTREG

    The IContextMenu interface does not have a proxy/stub factory (as of this writing). Recall that shell objects, as a rule, are apartment model. If you create the object from a multi-threaded apartment, COM needs to build a wrapper object which can marshal calls from off-thread back onto the original thread, in order to adhere to the threading rules for apartment-model objects.

    And if the COM standard marshaler can't find a proxy/stub factory for an interface, it returns the error REGDB_E_IIDNOTREG.

  • The Old New Thing

    If you have full trust, then you can do anything, so don't be surprised that you can do bad things, too


    This is another example of the dubious security vulnerability known as wrapping a simple idea inside layers of obfuscation and then thinking that somehow the obfuscation is the source of the problem.

    First of all, consider this: Suppose a program calls one of its own functions but gets the calling convention wrong and ends up corrupting its stack. Is that a security vulnerability in the operating system? No, it's a bug in the program. Now, maybe a bad guy can try to exploit this bug in the program, but if such an exploit could be found, it's naturally a vulnerability in the program, not in the operating system.

    Okay, now we add the layers of obfuscation.

    First, instead of calling the function incorrectly, we filter it through another function that takes a callback function. For example, let's use EnumFonts, which is a function that takes a callback function which is called once for each font. If you pass a callback function that has the wrong calling convention, that's your problem. The EnumFonts function doesn't know what calling convention your callback function uses; it's your responsibility to pass a correctly-formed function.

    Okay, let's add another layer of obfuscation. Instead of passing an incorrect callback function from unmanaged code, let's use DllImport to call the EnumFonts function from a VB.NET program. We're still passing an invalid callback function, but now it's being done from a VB.NET program instead of an unmanaged program.

    At this point, you announce that you have found a security vulnerability in VB. And since a lot of scripts are written in VB, you add that this vulnerability affects Word, Excel, Web pages, anything that supports script.

    But if you take away all the layers of obfuscation, you see that all that is really going on is that the program called a function with the wrong calling convention. Hardly an earth-shattering vulnerability.

    Now let's look to see if the layers of obfuscation made the original problem broader in scope. First of all, the caller and the crash take place in the same process, so we haven't crossed a security boundary from, say, one process to another, or from user mode to kernel mode. Furthermore, in order to call a DllImported function, the program needs to have full trust, in which case it already can do bad things to your computer without having to enlist the assistance of the EnumFont function. It could just start passing totally bogus parameters to Marshal.Copy and corrupt memory all it wants. The only interesting thing would be if a trusted program could somehow be tricked into passing a bogus function pointer to EnumFonts or otherwise be tricked into calling a bogus function, but even in that case, it would be a bug in that trusted program, not in VB itself.

  • The Old New Thing

    If you didn't like the answer, asking the same question again is unlikely to help


    I find it surprising how often this happens. A customer liaison will send a question to a mailing list like this:

    From: X
    To: Gizmo Discussion

    Hi, everybody.

    My customer is using the Gizmo Toolkit and wants to frob a gizmo without first registering as a frobber. They created the gizmo with CreateGizmo, passing all the default flags, and then they call AttachGizmo to attach the gizmo to a sprocket. When the sprocket detects that its host is decycling, it tries to frob the gizmo by calling FrobGizmo, but the call fails. They can't register the sprocket as a frobber because the sprocket doesn't have the right frob context. They tried setting the DefaultFrobContext registry key to Any but that didn't help. How can they frob the gizmo?

    Somebody from the Gizmo team will reply, "Sorry, but you have to register as a frobber before you can frob a gizmo. The DefaultFrobContext registry key doesn't help you here; it's for cogs, not sprockets. There is no analogous registry key for sprockets, sorry."

    That seems to be the end of it; there is no further response. Then about two weeks later, some other person will ask a suspiciously similar question.

    From: Y
    To: Gizmo Discussion

    Hello. I hope somebody can help us with this.

    My customer is using the Gizmo Toolkit and wants to frob a gizmo without first registering as a frobber. They created the gizmo with CreateGizmo, passing all the default flags, and then they call AttachGizmo to attach the gizmo to a sprocket. When the sprocket detects that its host is decycling, it tries to frob the gizmo by calling FrobGizmo, but the call fails. They can't register the sprocket as a frobber because the sprocket doesn't have the right frob context. They tried setting the DefaultFrobContext registry key to Any but that didn't help. How can they frob the gizmo?

    Hm, that question looks awfully familiar, let me look in the archives and... hey, it's a word-for-word copy of the same question somebody else asked two weeks ago!

    In situations like this, I tend to respond by attaching the original reply with the text, "I refer the honourable gentleman to the answer given some moments ago."

    Okay, maybe the customer was not happy with the answer and instead of elaborating on their situation (so somebody might be able to spot an alternate design that avoided this problem), they just reopened the case and got a different liaison the second time. Maybe person Y was simply duped into asking the same question.

    And then this happens.

    From: Y
    To: Windows Programming Discussion


    My customer is using the Gizmo Toolkit and wants to frob a gizmo without first registering as a frobber. They created the gizmo with CreateGizmo, passing all the default flags, and then they call AttachGizmo to attach the gizmo to a sprocket. When the sprocket detects that its host is decycling, it tries to frob the gizmo by calling FrobGizmo, but the call fails. They can't register the sprocket as a frobber because the sprocket doesn't have the right frob context. They tried setting the DefaultFrobContext registry key to Any but that didn't help. How can they frob the gizmo?

    Okay, so much for the theory that person Y was a victim. Person Y is clearly fishing around, hoping that if you ask the right person, you'll get an answer you like. It's sort of like the teenager who asks his father, "Can I borrow your car?" When Dad says, "No," the teenager goes to his mother and asks, "Can I borrow Dad's car?" in the hopes that maybe Mom will give a more favorable answer than Dad.

    But if you're asking a question about the Gizmo Toolkit, it's going to get routed to the Gizmo team one way or another. And if you ask the same, identical question, you're going to get the same, identical answer, just with a greater degree of exasperation each time you ask it again.

    "Can I have a pony?"
    — No
    "Can I have a pony?"
    — No.
    "Can I have a pony?"
    — No.

    Let me draw you a picture.

  • The Old New Thing

    May the Horse Be With You: Stories from the racetrack


    Only a Game interviews Harvey Pack [real], author of May the Horse Be With You, a collection of stories about horse racing. I don't really care much about horse racing, but I do love a good story, and Harvey Pack has a bazillion good stories.

  • The Old New Thing

    Why isn't the screen resolution a per-user setting?


    Via the suggestion box, Dominic Self asks why screen resolution is a global setting rather than a per-user setting. Well, first of all, it's not even a global setting. It's a session setting.

    That it's not a global setting is not readily apparent most of the time since only Windows Terminal Server is set up to support multiple simultaneous interactive sessions. On Windows Terminal Server, you specify the properties of the virtual monitor you wish to connect with, including resolution, and the server accommodates your wishes. Well, up to a point. I mean if you ask for a 1,000,000×1,000,000 pixel screen, the server is probably going to say "As if!" (The Remote Desktop Connection feature found in, for example, Windows Vista Ultimate is basically the same thing, but on a smaller scale.)

    You can have ten different people logged on, each using a different video configuration. Some users might be running at lowly 640×480, others at 800×600 and still others at 1024×768. Some of them are running in 16-color mode, others 8-bit color, and some really adventuresome people with a lot of network bandwidth running at 24-bit color. You can even have the same user logged on more than once, with each session running at a different screen resolution.

    If the resolution settings really were per-user, you'd have some conflict resolution to deal with. If a user logs on and specifies a resolution different from the one stored in the user profile, does the new resolution overwrite the existing one? Or is the new resolution just a temporary resolution and the original one should stay? If a user tries to log on a second time with a conflicting resolution, is the second resolution ignored? Does the second resolution force the first session to change its resolution? Do you just get two sessions running with different resolutions? Which one gets saved as the user's preferred resolution?

    You also have to come up with a way to customize the resolution of the screen when nobody is logged on, a way to reconcile the effect of roaming profiles, what happens if you do a Run As on a user whose screen resolution conflicts with the user who opened the session.

    I'm not saying that these problems can't be solved. They probably can, given enough thought, but not all of the solutions will please everybody all the time, because no matter what you do, somebody will tell you that you're an idiot. And think of all the time and effort necessary to design how the feature should work, nail all the boundary conditions ("What happens if your per-user setting conflicts with an administrative policy?"), then code it up, write automated tests for it, run it through usability exercises ("Does the behavior match what users intuitively expect?" The answers may surprise you.) write up the documentation and help text, and continue maintaining the code, tests, and documentation for the feature's anticipated lifetime (which in this case is probably forever). Could all those resources have been spent on something that would have a greater total benefit to the customer base? (The answer to that is always "Yes"—everybody and her sister-in-law can find a way to finish the sentence, "I can't believe they wasted all that time on this stupid feature instead of fixing...")

    Remember, every feature starts with minus 100 points.

  • The Old New Thing

    You cannot pre-emptively reserve a file extension


    The following question came in from a customer:

    If our program isn't installed and users double-click our document, they get sent to a Web site that presents a list of programs, but we want to send the user directly to our download site. How do we claim a file extension for our application?

    Um, you don't.

    You cannot pre-emptively reserve a file extension. If your program uses the extension .ABC and somebody off in another country working out of a garage also uses the extension .ABC, then that's fine. Of course, things get exciting when a user installs both your program and the garage program, but that's a conflict for the user to resolve. It is not your position to declare unilaterally that you are more important than that person in a garage.

    What you can do is list your program among the ones that support the .ABC extension, so that when the user double-clicks an .ABC document and no program is installed to handle it, the user is sent to a Web page that includes your program as one which can open that file. But this doesn't grant you exclusivity. You'll just show up on the list with everybody else who wants to claim that file extension.

  • The Old New Thing

    If you're at a Thai restaurant with a Thai person who's ordering food in Thai, and she asks you if you like your food spicy, think twice before answering


    I think you see where this is going.

    I'm at a Thai restaurant with my sister-in-law, who is Thai. She's talking with the waitress in Thai, and she discovers that the restaurant's cook is someone she knows. And since she's from Thailand, she assumes the task of ordering the food, since she knows what's good and what isn't.

    During their conversation (entirely in Thai, so I don't understand a word of it), she turns to me and asks, "So, is spicy food okay?"

    I say, "Yeah, I like spicy food."

    Classic rookie mistake.

    I think that by the end of the meal, I had just started to regain the ability to taste the food.

    Happy birthday, P—! And you'll be relieved to know that I can taste food again.

  • The Old New Thing

    What is this magic setting that synthesizes Unicode from non-Unicode?


    Commenter dan g. wonders how Windows can treat non-Unicode applications as Unicode via the Regional and Language Options control panel, specifically the part that lets you choose the Language for non-Unicode programs. "Having always believed that the only way to display, say, Chinese characters correctly was to compile with _UNICODE, this facility seems all the more remarkable."

    This setting is really not as magical as it appears. (After all, we had Chinese versions of 16-bit Windows that displayed Chinese characters just fine, and they certainly didn't use Unicode since Unicode hadn't been invented yet.) Michael Kaplan went through this and many other settings in the Regional and Language Options control panel, and from the chart at the top of the page, you see what Windows XP calls the Language for Non-Unicode Programs used to go by the name Default System Locale. The old name does a better job of describing what it actually does but does a worse job of describing what it's used for.

    In Win32, three character encodings have special status. Unicode (more precisely, UTF-16) of course is what Windows uses internally. There are also two 8-bit code pages: CP_ACP, the so-called ANSI code page (even though it isn't actually ANSI), and the CP_OEM code page, the so-called OEM code page (even though it isn't provided by the OEM).

    When a non-Unicode program calls a function like TextOutA to display a string represented in the ANSI code page, the string is converted to Unicode via the CP_ACP code page. The Language for non-Unicode programs setting controls what code page CP_ACP corresponds to. On U.S. systems, it's typically code page 1252, but you can change it via that control panel. And that's where it becomes possible to display Chinese characters without using Unicode.

    For example, code page 950 is a double-byte code page commonly seen in countries that use traditional Chinese characters. It can represent the English alphabet of A-Z, and through the use of double-byte characters can also represent a wide array of traditional Chinese characters, such as this block of characters which are represented by byte sequences of the form B3 40 through B3 FE. If the ANSI code page is code page 950 and you pass data formatted for that code page to, say, the TextOutA function, the corresponding Chinese characters will display, even though the program itself doesn't use Unicode explicitly.

    That's why it's called the Language for non-Unicode programs. It specifies which character set non-Unicode data should be interpreted as.

  • The Old New Thing

    The day shell.windows.com went down


    When the file association Web service was first being developed, the programmer responsible for implementing the feature just scrounged around and found an old unused computer and set it up as a simple Web server under his desk, so there would be something to test the code against. That server happily churned away serving out file extension information, and when people asked for their program to be added, he would manually add it to the server. The server worked just fine, and like most things which work just fine, it was forgotten.

    And then remembered once things no longer worked just fine.

    I think it was during one of the beta cycles, or maybe it was RC1, when the quiet neglected computer went offline. I forget why, so let's pretend that the programmer unplugged it as part of an office redecoration project. Suddenly, the shell.windows.com service went down.

    What? The file association Web service went down?

    Everybody had forgotten that shell.windows.com was still running on a computer under that programmer's desk. It had done such a good job up until now that nobody gave it a second though.

    He plugged the computer back in and watched the server bang out requests like nobody's business.

    Wheels were quickly set into motion to transfer the file association Web service to a machine with a little bit more professional attention and maintenance.

  • The Old New Thing

    Excessive speed appeared to be a factor in the crash


    In February 2007, a serious automobile accident took place in southwest Washington. A twelve-year-old boy was at the wheel of an SUV when he lost control and struck another vehicle. According to the sheriff's office, "Excessive speed appeared to be a factor in the crash." I dunno, I think a major factor is that a twelve-year-old was behind the wheel.

    Tragically, the boy sustained critical injuries and died the following day. There was an adult in the car who conveniently doesn't remember what happened, although there are rumors that this wasn't the first time that adult let the boy drive, and that the boy had remarked to a friend that "he always drove to school." Okay, what adult lets a twelve year old boy drive a car? Apparently, he was permitted to drive because he asked to.

    News flash: There are times when the correct answer is "No".

    Follow-up: Court documents cite witnesses who claim "the boy had driven several times, at speeds up to 80 miles an hour." It was noted in passing in May 2007 that the adult pled not guilty to vehicular manslaughter charges.

    Conclusion: As part of a plea agreement, the adult was sentenced to five years in prison plus probation.

Page 2 of 4 (34 items) 1234