Containment Delegation  «Prev  Next»

Debug containment/delegation code - Exercise

Objective: Find the bug in an outer COM object's code.

Instructions


Following is pseudo-code for an outer COM object. Both the outer COM object and the inner COM object implement interface IX1 as described above. The outer COM object delegates to IX1 in the inner COM object.
This code has a bug in it. Find and fix the bug.
class OuterCOMObj_ClassFactory : IClassFactory {
...
  HRESULT CreateInstance
    (IUnknown *po, REFIID riid, void **ppv)   {
    BOOL bInit;
    HRESULT hr = E_FAIL;
     //Create the COM object
     OuterCOMObj *pcom = new OuterCOMObj();
     if (!pcom) return E_OUTOFMEMORY;

     //Call the Init method. This is NOT a COM call.  
     //It is simply an internal initialization call.
     bInit = pcom->Init();
     if (bInit) hr = pcom->QueryInterface(riid, ppv);

     if (FAILED(hr) || !bInit) delete pcom;

     return hr;
   }
   ... Other Code ...
 };

 
class OuterCOMObj : IX1, IX2 {
  ULONG m_refcnt;
  IX1 *m_pInner_IX1;

public:
  OuterCOMObj() : m_refcnt(0), 
     pInner_IX1(NULL) { }
   ~OuterCOMObj { }

  //Called from IClassFactory::CreateInstance to perform internal initialization of the COM 
  //object. This is where the outer COM object
  //creates an instance of the inner COM object 
  //and gets an interface pointer into it.
  
  BOOL Init()  {
  //Create an instance of the inner COM object 
  //and get a pointer to its IX1 interface.
  //Place the inner COM object's IX1 pointer 
  //in m_pInner_IX1.
     
      HRESULT hr = 
         CoCreateInstance(CLSID_InnerCOMObj, 
            NULL, CLSCTX_INPROC_SERVER,
            IID_IX1, (void **) &m_pInner_IX1);

      if (FAILED(hr)) return FALSE;
       return TRUE;
 }

 HRESULT QueryInterface(REFIID riid, void **ppv) {
    if (riid == IID_IX1)   *ppv = (IX1 *) this;
    if (riid == IID_IX2)   *ppv = (IX2 *) this;
    else return E_NOINTERFACE;
       
    ((IUnknown *) (*ppv))->AddRef();
    return S_OK;
}

 HRESULT AddRef() { return ++m_refcnt; }
 HRESULT Release()  {
      if (--m_refcnt == 0) {
         delete this;
         return 0;
       }
       return m_refcnt;
   }
  //IX1 Functions
  HRESULT x1(int ix) {
      //Delegate to the inner object's IX1::x1
      return m_pInner_IX1->x1(zz);
  }
  //x2 filters it delegation - calling into the 
  //inner object every other time
  HRESULT x2() {                
     static int even_odd = 1;
     HRESULT hr = S_OK;    
     if (!(even_odd % 2))      {
        //Delegate to the inner object's IX1::X2
        hr = m_pInner_IX1->x2();
     }
     else { ... do stuff ..    }
     ++even_odd;
     return hr;
   }

   //IX2 Functions
  Assume IX2 is an interface implemented 
  by the outer COM object. For this exercise 
  we are not concerned with its implementation.
};

Exercise scoring


This exercise is worth 20 points.

Exercise submission


Write or paste your answer in the text area below. When you are done, click Submit to submit your answer.