Yo dawg, I hear you like COM apartments, so I put a COM apartment in your COM apartment so you can COM apartment while you COM apartment

Raymond Chen

Last time, we learned about COM apartments, with the two main flavors the single-threaded apartment and the multi-threaded apartment. But it turns out you can also create “miniature apartments” inside your apartment. (Is this like Airbnb for COM or something?)

This “miniature apartment” is formally known as a COM context and goes by the name CLSID_Context­Switcher. You create one by calling

IContextCallback* context;
CoCreateInstance(CLSID_ContextSwitcher, nullptr,
    CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&context));

You can then enter the context by calling the IContext­Callback::Context­Callback method with a function you would like to execute inside that context. I’m going to postpone further discussion of the IContext­Callback::Context­Callback method to another article, because the IContext­Callback::Context­Callback method is kind of weird, and untangling it will take a while.

Back to contexts. Why would you want to create a custom context anyway?

The original audience for custom contexts was Windows NT services which expose COM objects to clients. Services also have to respond to shutdown requests. This puts them in a bit of a pickle: They are required to clean up and unload from the process when given a shutdown request,¹ but they also cannot unload (under penalty of access violation) until all clients have released their references to objects in the service.

The solution is for the service to create a private little COM context for its objects. It then enters the context and registers its object factory. When a client requests an object, the factory will be called to produce the desired object. Since the factory is inside a context, the resulting object will also be inside that same context. The client receives a proxy object that talks to the object living inside the context.

Context
object proxy ←Client

When the server is told to shut down, it enters the context one last time to revoke its factory and call Co­Disconnect­Context. The Co­Disconnect­Context function disconnects all outstanding proxies from the underlying objects, erasing the arrow from the proxy to the object:

Context
object proxy ←Client

The expectation is that disconnecting all the proxies will cause the reference counts of all the objects in the context to drop to zero, and everything will be destroyed. The service can destroy the context, and everything that had references to the service DLL is now gone, thus allowing the service DLL to unload itself from memory.

Meanwhile, the clients are left holding a broken proxy. Any attempt to access the underlying object from the proxy wll return the error RPC_E_DISCONNECTED.

Although Windows NT Services were the original audience for private contexts, they are not the only valid use for them. Next time, we’ll look at another way they can become useful.

¹ This means that the shutdown “request” is more like a shutdown “demand”.

8 comments

Discussion is closed. Login to edit/delete existing comments.

  • Alex Martin 0

    I wonder how many services there are out there that just don’t respond to shutdown requests.

    • Harry Johnston 0

      Provided they don’t register to receive them, they don’t have to. They can continue to run until Windows actually turns the power off, and in fact this is the recommended behaviour per the documentation, I assume because exiting the process would typically consume more resources than just allowing it to keep running.

      (This was even more curious back in the days before ACPI; you could write a service and have it continue to run, and potentially even interact with the user, while the “It is now safe to turn off your computer” screen was up.)

  • Henke37 0

    I think there is something missing from this post. That COM will automatically disconnect the proxies when COM is shutting down for the process. The keyword here being “the process”. If you are doing a service that is doing traditional svchost process sharing then you can’t do that. That’s what contexts solve here.

    • Danstur 0

      That explains it, I was confused why they needed to do anything extra since disconnecting at process destruction seems like the obvious default anyhow.

  • Thad House 0

    Unrelated to this post (Although awesome read), but can you fix up the links on this page?

    https://devblogs.microsoft.com/oldnewthing/20060727-04/?p=30333

    It would awesome to read through all of those, I want to learn more, but all the links are broken, and I can’t find them manually.

    • Nick Allmaker 0

      Hover over the archive links down at the bottom of the page and they’re all in the format `https://devblogs.microsoft.com/oldnewthing/year/month`. That post has links which also has dates in them, so check the July 2006 archives for the posts you’re looking for: https://devblogs.microsoft.com/oldnewthing/2006/07

  • Ryan P 0

    I have been coding COM objects for years, but I never knew this context feature existed. In my NT service that hosts a COM server, I simply keep track of the number of COM objects that have been requested by clients and have not been released yet, and then I have the service reject SERVICE_CONTROL_STOP requests if there are any active COM objects.

  • Vasilios Magriplis 0

    That’s one heck of an old meme in the title, but apt nonetheless!

Feedback usabilla icon