IShellFolder::BindToObject is a high-traffic method; don’t do any heavy lifting


A customer observed that once the user visited their shell extension, Explorer ran really slowly. (Actually, it took a while just to get to this point, but I'll skip the early investigations because they aren't relevant to the story.) Some investigation showed that Explorer's tree view was calling into the shell extension, which was in turn hanging the shell for several seconds at a time.

Explorer was calling into the shell extension because the node was in the folder tree view, and Explorer was doing a little bookkeeping to synchronize the folder state with the view. The node referred to a server that was no longer available, so when Explorer asked the shell extension, "Hey, do you have any translucent froodads for me?" the shell extension went off and tried to contact the server (30 second timeout) before returning with the answer, "Um, sorry, I'm not sure what you're talking about."

The problem was in the shell extension's IShell­Folder::Bind­To­Object method. The Bind­To­Object method is how you navigate from a parent to a child object, but this is supposed to be a lightweight navigation. Don't try to validate that the child still exists. Just bind to the child as if it existed. Only when the client tries to do something interesting should you go check whether the object actually exists.

You can see this in the shell, for example. Suppose you generate a pidl to a network server. Meanwhile, the network server goes down. If you try to bind to that pidl, the bind will succeeed (and quickly). Only if you then ask a question like Enum­Objects will you find out, "Oh, wait, this server doesn't actually exist."

(Validating existence on bind doesn't really buy you much anyway, because the server might go down after the bind succeeds but before the Enum­Objects call, so clients have to be prepared anyway for the possibility of a successful bind but a failed enumeration.)

In the shell, binding is a common operation since it's a prerequisite for talking about objects. As long as the pidl is valid, you should succeed the bind. Try not to hit the disk and definitely don't hit the network. There's plenty of time to do that later. Because the bind may not even have been done with the intention of communicating with the target; the client may have bound to the pidl just to be able to talk about the target. (As in this case, where the shell wasn't interested in the target per se; it just wanted to know if the target had a translucent froodad.)

Comments (6)
  1. Froo dat says:

    Is there any Windows documentation on translucent froodads? They sound like an awesome feature that I'd like to use in my next shell extension, but the only MSDN search result is for this page.

  2. Validating existence on bind doesn't really buy you much anyway, because the server might go down after the bind succeeds but before the Enum­Objects call, so clients have to be prepared anyway for the possibility of a successful bind but a failed enumeration.

    Me, on phone to Wal-Mart: I want to buy a king-sized mattress, but before I drive out there, do you have any in stock?

    Wal-Mart (immediately): oh, yeah, sure.

    Me: you didn't even go look!

    Wal-Mart: well, even if I did go look, we might sell them all before you get to the store, so you have to be prepared anyway for the possibility of a successful phone check but a failed in-store check… so I just always say we have everything in stock, which vastly improves my calls-handled-per-hour.

  3. Jonathan says:

    I wonder if there's an AppVerifier Shim/Check to catch such violations. I can envision one – mark thread as "should return quickly" before entering BindToObject implementation, and fail the check if it calls any disk/network-hitting API during that time.

    @Maurits: Nice. I guess the actual analogy would be:

    Me: Do you guys sell mattresses?

    Walmart guy: I'll check what we have…

    Me: No need, I just…

    Walmart: (Annoying hold music for 3 minutes, while the guy makes a complete inventory list of every mattress in stock and on display)

    Walmart: Yes we do! Here's the complete list…

    Me: No need, just wanted to know whether you generally do.

    The solution to the "successful phone check but a failed in-store check" is an atomic resource lock: "If you have any, please reserve one for me". Of course, that is vulnerable to abandoned resources (I don't show up, item is reserved until timeout), DOS (100 people reserve and now Walmart can't sell any), DDOS (I advertise for people to call and DOS Walmart), etc.

  4. Anonymous Coward says:

    The problem is that msdn.microsoft.com/…/bb775059(v=vs.85).aspx doesn't give much guidance in this direction to implementers.

  5. stasoid says:

    What is froodad? Can't find translation.

  6. JM says:

    @stasoid: a froodad is a frozen doodad. The doodad, in turn, is a kind of thingummy, thingamajigger, whatchamacallit — kin to gizmos, doohickeys and widgets.

Comments are closed.