IClassFactory::CreateInstance

The class factory-specific functions are really all that are interesting. CreateInstance in this example will create an instance of the CTextRender object and return an interface pointer to it as shown below. Note that if pUnkOuter is non-NULL, that is, another object is attempting to aggregate, this code will fail with CLASS_E_NOAGGREGATION (this limitation will be revisited when later when aggregation is discussed).


//A global variable that counts objects being served
ULONG    g_cObj=0;

HRESULT CTextRenderFactory::CreateInstance (IUnknown * pUnkOuter, REFIID iid, void ** ppv) {
   CTextRender *       pObj;
   HRESULT             hr;

   *ppv=NULL;
   hr=E_OUTOFMEMORY;
   if (NULL!=pUnkOuter)
      return CLASS_E_NOAGGREGATION;

   //Create the object passing function to notify on destruction.
   pObj=new CTextRender(pUnkOuter, ObjectDestroyed);
   if (NULL==pObj)
      return hr;

   [Usually some other object initialization done here]

   //Obtain the first interface pointer (which does an AddRef)
   hr=pObj->QueryInterface(iid, ppv);

   //Kill the object if initial creation or FInit failed.
   if (FAILED(hr))
      delete pObj;
   else
      g_cObj++;

   return hr;
   }

There are two interesting points to this code, which is fairly standard for server implementations. First of all, note the call to the object's QueryInterface after creation. This accomplishes two things: first, since objects are generally constructed with a reference count of zero (common practice) then this QueryInterface call, if successful, has the effect of calling AddRef as well, making the object have a reference count of one. Second, it lets the object determine if it supports the interface requested in iid and if it does, it fills in ppv for us.

The second key point is that COM defines no standard mechanism for counting instantiated objects (there is no need for such a generic service), so this implementation example maintains a count of the objects in service using the global variable g_cObj. This count generally needs to be global so that other global functions can access it (see "Providing for Server Unloading," below). When CreateInstance successfully creates a new object it increments this count. When an object (not the class factory but the one the class factory creates) destroys itself in its implementation of CTextRender::Release, it should decrement this count to match the increment in CreateInstance.

It is not necessary, however, for the object to have direct access to this variable, and there are techniques to avoid such access. The example above passes a pointer to a function called ObjectDestroyed to the CTextRender constructor such that when the object destroys itself in it's Release it will call ObjectDestroyed to affect the server's object count:


void ObjectDestroyed(void) {
   g_cObj--;
   [Initiate unloading if g_cObj is zero and there are no locks]
   return;
   }

CTextRender::CTextRender(void (* pfnDestroy)(void)) {
   m_cRef=0;
   m_pfnDestroy=pfnDestroy;
   [Other initialization]
   return;
   }

ULONG CTextRender::Release(void) {
   ULONG       cRefT;
   cRefT=--m_cRef;
   if (0L==m_cRef) {
      if (NULL!=m_pfnDestroy)
         (*m_pfnDestroy)();
      delete this;
      }
   return cRefT;
   }

The object might also be given a pointer to the class factory object itself (which the object will call AddRef through, of course) that accomplishes the same thing. Regardless of the design, the point is that the object can be designed so as to be unaware of the exact object counting mechanism, having instead some mechanism to notify the server as a whole about the destroy event. A standard mechanism for this is not part of COM.

You might have noticed that the ObjectDestroyed function above contained a note that if there are no objects and no locks on the server, then the server can initiate unloading. What really happens here depends on the type of server, .DLL or .EXE, and will be covered under "Providing for Server Unloading."