Practial ATL: Implementing a non-standard class object

In my previous article in this series, I explained how class objects are associated with COM objects, and how it all fits together.

Armed with that knowledge, I can now demonstrate how to provide a custom class object that will allow us to support parameterized construction.

If you haven’t already read my previous article on class objects, please do so first because I am going to assume you did J

The non-standard class object interface: IStuffCreator

A class object can have any interface you want, just like the COM object we have created earlier. It is just another COM object after all. My custom interface looks like this:

      helpstring(“IStuffCreator Interface”),
interface IStuffCreator : IUnknown {
  [id(1), helpstring(“method MakeMeAStuff”)]
    HRESULT MakeMeAStuff(
      [in] BSTR name,
      [in] REFIID riid,
      [out, iid_is(riid)] IUnknown** ppStuff);

The bits between the square brackets are the attributes that are applied to this interface. ‘Object’ specifies that it is a COM interface. The uuid specifies the GUID that identifies the interface. ‘oleautomation’ specifies that the arguments being used are all automation compatible. The meaning of  ‘helpstring’ is pretty obvious, and pointer_default specifies the assumptions that the marshaller can make about pointers.

If you want to know the details about it, then have a look in MSDN for MIDL attributes.

The interface itself is very simple. Instead of deriving from IDispatch like the IStuff interface, this interface derives from IUnknown. Deriving from IDispatch would only complicate matters without any benefit.

The interface has only one method, which is responsible for handing out new stuffs.

The parameter that will be used for constructing the CStuff instance itself is the ‘name’ parameter. If the CStuff would need multiple parameters, they would have to be part of the parameter list so that they can be used at the time of construction. The riid and ppStuff parameters have the same meaning as those of CoCreateInstance.

The declaration of CStuffCreator

If we want to implement this interface, we add a new C++ class with the name ‘CStuffCreator’ to our project, and implement our IStuffCreator interface

class CStuffCreator:
  public IStuffCreator,
  public CComObjectRootEx<CComGlobalsThreadModel>

  virtual ~CStuffCreator(void){}


  //IStuffCreator methods
    BSTR name,
    REFIID riid,
    IUnknown **ppStuff);

  // helper method
  void SetVoid(void* pv);
  _ATL_CREATORFUNC* m_pfnCreateInstance;

As you can see, it is pretty simple. The CComObjectRootEx base class helps with reference counting, and is the same that is used by the other COM objects in our project.

We add IStuffCreator to the interface map using the ATL macros, and then we simply declare the single MakeMeAStuff method that we need to implement.

The SetVoid method and the function pointer are part of the default C++ interface for class objects in ATL, and are explained in my previous article.

The implementation

The implementation of CStuffCreator is even simpler than the declaration:


  BSTR name,

  REFIID riid,

  IUnknown **ppStuff)


  CComPtr<IUnknown> newStuff;

  HRESULT hr = m_pfnCreateInstance(

                 NULL, __uuidof(IUnknown), (void**)&newStuff);


    return hr;


  return newStuff->QueryInterface(riid, (void**)ppStuff);



void CStuffCreator::SetVoid(void* pv)


  m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;


Ignore the ‘name’ parameter for now. That will be used when we are going to initialize the new instance. The bare functionality of our class object is to use the function pointer to create a new instance. I could have done this in 1 step instead of 2 (the QueryInterface isn’t necessary at this point) but this way I can slide in some additional functionality later on.

And you can see now that the class object will receive the creator function pointer via the ‘SetVoid’ method. This mechanism was explained in my previous article.

Parameterized construction

The point of using a non-standard class object in this demonstration was to be able to create objects that need some sort of initialization before the client has access to them. Normally, ATL supports only default constructors using, because IClassFactory is a generic interface.

For parameterized constructors, we are going to have to do something special.

There are essentially 2 ways we can do this. The first is to change CStuff to have a parameterized constructor. But ATL can’t handle that, and it would mean we have to abandon the incredible convenience of being able to use the ATL::Creator<T> class, ATL::CComObject class, and other helper classes that take the pain out of COM.

Don Box wrote an article about parameterized construction, many years ago, and this was the approach he took. Of course, ATL was much simpler in those days, and abandoning it was perhaps less of an inconvenience.

The approach I am taking is much simpler: I cheat!

That’s right. I cheat. I am not going to implement parameterized constructors. I am going to fake it. But from the client’s point of view, it’s going to look exactly the same, so he won’t mind. And from the server’s point of view, it will be much simpler to implement, so everybody wins.

The second approach to implementing parameterized construction is to implement an internal interface on CStuff, which will be used for initializing it. The new CStuff instance will not be accessible to anyone until the first interface pointer is handed out by the class object. And we are the ones implementing the class interface, so we can make sure that the new instance is initialized properly before it is released into the wild.

The initialization interface

The interface for initializing a CStuff is pretty simple (I left out the header for clarity):

interface IStuffInit : IUnknown {

  [id(1), helpstring(“method InitStuffInstance”)]

    HRESULT InitStuffInstance(

      [in] BSTR Name);


Our CStuff instances are supposed to have a name, so that’s what needs to be in the init interface. If they would also need an address, a hat, and a pair of pants, we would have to put those in the parameter list of the InitStuffInstance method as well.

Implementing the initialization interface

Implementing the interface in CStuff is easy I highlighted the changes that have to be made to the declaration.

// CStuff


class ATL_NO_VTABLE CStuff :

  public CComObjectRootEx<CComMultiThreadModel>,

  public CComCoClass<CStuff, &CLSID_Stuff>,

  public IDispatchImpl<IStuff, &IID_IStuff, &LIBID_Stuff_ServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,

  public IStuffInit



  CComBSTR m_Name;




// removed irrelevant stuff








// removed irrelevant stuff



First we add IStuffInit to the inheritance list, we add it to the COM map, and then we add the declaration for InitStuffInstance.

Of course, the name has to be part of the objects state, so we add a CComBSTR variable to hold it.

And finally, we use the DECLARE_CLASSFACTORY_EX macro to change the class object for CStuff from CComClassFactory to CStuffCreator.

The actual implementation of the interface consists of the simple code

STDMETHODIMP CStuff::InitStuffInstance(BSTR Name)


  m_Name = Name;

  return S_OK;


Note the ease with which CComBSTR allows us to perform simple string operations.

Initializing the new CStuff object

Now that there is a dedicated function to handle the initialization, the changes to CStuffCreator are trivial:


  BSTR name,

  REFIID riid,

  IUnknown **ppStuff)


  CComPtr<IStuffInit> newStuff;

  HRESULT hr = m_pfnCreateInstance(

                  NULL,__uuidof(IStuffInit), (void**)&newStuff);


    return hr;


  hr = newStuff->InitStuffInstance(name);


    return hr;


  return newStuff->QueryInterface(riid, (void**)ppStuff);


What about double initialization

By now you might be wondering: But what if the client application retrieves this interface and performs another initialization?

However, this will not be possible.

It’s true that I put the interface in our IDL file, and that I implemented it in the CStuff object. But I did not put that interface in the library declaration, nor did I put it in the interface list of the coclass.

So for all practical purposes, this interface is not accessible to the client application. If you are really paranoid, you could argue that an attacker might know the interface GUID, and guess the interface definition, and with some trial and error make it work.

Even then, the fix is quite simple. You can add a boolean to your class that indicates if the object was initialized or not. Set it to false in the constructor, and then the InitStuffInstance can either perform initialization if it is false and set it to true, or return E_FAIL if it is already true.

You don’t even have to care about race conditions, because there aren’t any. Only the class object can perform the real initialization. And since no one else has an interface pointer yet, there can’t be a race.

The client side

Creating a new CStuff has changed a little bit, because now we can’t use CoCreateInstance anymore. So construction is now done in 2 stages:

    CComPtr<IStuffCreator> stuffClass;

    hr = CoGetClassObject(

           __uuidof(Stuff), CLSCTX_ALL, NULL,

           __uuidof(IStuffCreator), (void**)&stuffClass);


      return hr;


    //make a new stuff   

    CComBSTR stuffName = L“Kato”;

    CComPtr<IStuff> newStuffUnk;

    hr = stuffClass->MakeMeAStuff(





      return hr;

It’s still very simple though. First we get the class object, and then we use the IStuffCreator interface to create the new CStuff.

Server lifetime management

Everything works, hip hip hurray… until you destroy the first CStuff instance, and then try to create another one. That is where it all goes pear shaped.

The problem is that we haven’t taken care of managing the lifetime of the server (the exe). The key issue here is the module lock reference count.

Each COM module (exe or dll) has a global reference count to keep track of how many objects are ‘alive’. COM objects exist physically inside a DLL or EXE. So the EXE has to stay alive as long as there are living objects inside. Conversely, as soon as there are no living objects anymore, the EXE should shut down.

What happens in our example is that CStuff raises the module ref count when it is created. And when the CStuff instance destroys itself, it lowers the module ref count. If you remember correctly, the class object itself uses CComObjectNoLock as its COM core. This means that its existence does not influence the module lifetime.

So when the CStuff instance destroys itself and lowers the module ref count, the ref count reaches 0 and the server EXE shuts down.

The client is unaware of this and tries to use the class object again. It still thinks it has a valid interface pointer, but the underlying class object is long gone and there will be a critical error in the client application.

You might say ‘well duh, then don’t use CComObjectNoLock, doofus’ but that has the opposite effect. The COM runtime will always have the interface pointer that was used for registering the class object with CoRegisterClassObject. This means that the class object would not destroy as long as the server lives. And the server would keep living as long as the class object was around. This is clearly not the answer.

IExternalConnection to the rescue

The key to solving this problem is a rarely used standard interface. IExternalConnection is an interface that can be used by an object to track how many external connections there are to itself. This is basically an alternative to the standard object reference count.

There are 2 methods in this interface:


                         DWORD extconn, DWORD dwReserved);

  STDMETHODIMP_(DWORD) ReleaseConnection(

                         DWORD extconn,

                         DWORD dwReserved,

                         BOOL bLastUnlockReleases);


If a client requests any class object, the COM runtime will retrieve it. But before the interface pointer is released to the client, it will request some interfaces itself for housekeeping purposes. One of those interfaces is IExternalConnection.

If a client requests an interface pointer to a class object, the marshaller will call AddConnection when it hands out the pointer, and ReleaseConnection when the pointer is destroyed.

So all we have to do is to make sure that a call to AddConnection will increment the module lock count, and a call to ReleaseConnection releases the module lock count.

Implementing IExternalConnection

If you look in MSDN, you won’t find it. It is undocumented, but the ATL headers contain an implementation for IExternalConnection. It’s called IExternalConnectionImpl<T>.

To use it, we only have to change CStuffCreator so that it inherits from it, and add it to the COM interface map.

class CStuffCreator:

  public IStuffCreator,

  public IExternalConnectionImpl<CStuffCreator>,

  public CComObjectRootEx<CComGlobalsThreadModel>




  //removed irrelevant stuff






  //IExeternalConnectionImpl<T> extension

  void STDMETHODCALLTYPE OnReleaseConnection(

         bool bThisIsLastUnlock, bool bLastUnlockReleases);

  void STDMETHODCALLTYPE OnAddConnection(

         bool bThisIsFirstLock);


  //removed irrelevant stuff


That is really all there is to it. The default implementation does not modify the module lock count. But it has 2 extension points that we can override. So that’s what we do to make sure the module lock count is managed properly.

void STDMETHODCALLTYPE CStuffCreator::OnAddConnection(

       bool bThisIsFirstLock)





void STDMETHODCALLTYPE CStuffCreator::OnReleaseConnection(

       bool bThisIsLastUnlock, bool bLastUnlockReleases)




    bThisIsLastUnlock,  bLastUnlockReleases);


The only special thing that still needs mentioning is that OnReleaseConnection delegates back to the default implementation in IExternalConnectionImpl. It does this because there is something that needs to be done when the last external connection is closed.

  void OnReleaseConnection(

       bool bThisIsLastUnlock, bool bLastUnlockReleases)


    if (bThisIsLastUnlock && bLastUnlockReleases)

         CoDisconnectObject(static_cast<T*>(this)->GetUnknown(), 0);


If the last connection closes, the class object needs to call CoDisConnectObject to destroy its marshalling stub. Now I could copy paste this code into my implementation of OnReleaseConnection, but it is simpler to just delegate back to the base class for stuff that needs doing anyway.

The result

Now that we have provided this implementation of IExternalConnection, the server EXE will stay alive until all CStuff instances are gone, and noone is using the class object anymore. Only then will the EXE terminate.

CComClassFactory revisited

If you look at the interface implemented by CComClassFactory, you’ll notice that IExternalConnection is missing. And yet, server lifetime of CComClassFactory is managed correctly.

The reason for this is that the COM runtime treats IClassFactory class objects differently from other class objects. It will check if the class object supports IClassFactory. And if it does, it calls IClassFactory::LockServer to indicate that someone is using the class object. And it unlocks the class object when the class object reference is released again.

In a way, it uses the IClassFactory in almost the same way as it would use IExternalConnection. And in a way it is too bad that this functionality was included in IClassFactory directly, instead of making IClassFactory inherit from IExternalConnection. The reasons for this are lost in the mists of time. But whatever the reasons, this is why IClassFactory doesn’t need IExternalConnection.


As you can see, implementing a non standard class object is not so hard. As long as you have a basic understanding of the underlying COM principles, ATL takes care of all the dirty work.

And by using these techniques, we can implement COM objects that need initialization before they can safely be used by the client. The source code for this article is available under the MIT license as usual.

And again I’d like to add a thank you for Microsoft’s Tim Springfield and Amit Mohindra



Leave a Reply

Your email address will not be published. Required fields are marked *