KOALA.CPP
/* 
 * KOALA.CPP 
 * Koala Object for EXE Servers, Chapter 6 
 * 
 * Implementation of an object with IExternalConnection. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#include "koala.h" 
 
 
/* 
 * CKoala::CKoala 
 * CKoala::~CKoala 
 * 
 * Parameters (Constructor): 
 *  pUnkOuter       LPUNKNOWN of a controlling unknown. 
 *  pfnDestroy      PFNDESTROYED to call when an object 
 *                  is destroyed. 
 */ 
 
CKoala::CKoala(LPUNKNOWN pUnkOuter, PFNDESTROYED pfnDestroy) 
    { 
    m_cRef=0; 
    m_pUnkOuter=pUnkOuter; 
    m_pfnDestroy=pfnDestroy; 
 
    //CHAPTER6MOD 
    m_cStrong=0; 
    m_cWeak=0; 
 
    m_pImpIPersist=NULL; 
    //End CHAPTER6MOD 
    return; 
    } 
 
CKoala::~CKoala(void) 
    { 
    //CHAPTER6MOD 
    DeleteInterfaceImp(m_pImpIPersist); 
    //End CHAPTER6MOD 
    return; 
    } 
 
 
 
/* 
 * CKoala::Init 
 * 
 * Purpose: 
 *  Performs any intiailization of a CKoala that's prone to failure 
 *  that we also use internally before exposing the object outside. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if the function is successful, 
 *                  FALSE otherwise. 
 */ 
 
BOOL CKoala::Init(void) 
    { 
    //CHAPTER6MOD 
    IUnknown   *pUnk=this; 
 
    if (NULL!=m_pUnkOuter) 
        pUnk=m_pUnkOuter; 
 
    m_pImpIPersist=new CImpIPersist(this, pUnk); 
 
    //No failure if m_pImpIPersist is NULL, QueryInterface will fail 
 
    return TRUE; 
    //End CHAPTER6MOD 
    } 
 
 
 
 
/* 
 * CKoala::QueryInterface 
 * CKoala::AddRef 
 * CKoala::Release 
 * 
 * Purpose: 
 *  IUnknown members for CKoala object. 
 */ 
 
STDMETHODIMP CKoala::QueryInterface(REFIID riid, PPVOID ppv) 
    { 
    *ppv=NULL; 
 
    //CHAPTER6MOD 
    if (IID_IUnknown==riid || IID_IExternalConnection==riid) 
        *ppv=this; 
 
    if (IID_IPersist==riid && NULL!=m_pImpIPersist) 
        *ppv=m_pImpIPersist; 
    //End CHAPTER6MOD 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CKoala::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
 
STDMETHODIMP_(ULONG) CKoala::Release(void) 
    { 
    if (0L!=--m_cRef) 
        return m_cRef; 
 
    if (NULL!=m_pfnDestroy) 
        (*m_pfnDestroy)(); 
 
    delete this; 
    return 0; 
    } 
 
 
 
 
//CHAPTER6MOD 
/* 
 * CKoala::AddConnection 
 * 
 * Purpose: 
 *  Informs the object that a strong connection has been made to it. 
 * 
 * Parameters: 
 *  dwConn          DWORD identifying the type of connection, taken 
 *                  from the EXTCONN enumeration. 
 *  dwReserved      DWORD reserved.  This is used inside OLE and 
 *                  should not be validated. 
 * 
 * Return Value: 
 *  DWORD           The number of connection counts on the 
 *                  object, used for debugging purposes only. 
 */ 
 
STDMETHODIMP_(DWORD) CKoala::AddConnection(DWORD dwConn 
    , DWORD dwReserved) 
    { 
    DWORD       dwRet; 
    TCHAR       szTemp[80]; 
 
    if (EXTCONN_STRONG & dwConn) 
        { 
        dwRet=++m_cStrong; 
        wsprintf(szTemp 
            , TEXT("AddConnection cStrong=%lu"), m_cStrong); 
        } 
 
   #ifdef WIN32 
    if (EXTCONN_WEAK & dwConn) 
        { 
        dwRet=++m_cWeak; 
        wsprintf(szTemp 
            , TEXT("ReleaseConnection cWeak=%lu"), m_cWeak); 
        } 
   #endif 
 
   #ifndef WIN32 
    ODS(szTemp); 
   #else 
    MessageBox(NULL, szTemp 
        , TEXT("EKoala3: CKoala::IExternalConnection"), MB_OK); 
   #endif 
 
    return dwRet; 
    } 
 
 
 
/* 
 * CKoala::ReleaseConnection 
 * 
 * Purpose: 
 *  Informs an object that a connection has been taken away from 
 *  it in which case the object may need to shut down. 
 * 
 * Parameters: 
 *  dwConn              DWORD identifying the type of connection, 
 *                      taken from the EXTCONN enumeration. 
 *  dwReserved          DWORD reserved.  This is used inside OLE and 
 *                      should not be validated. 
 *  dwRerved            DWORD reserved 
 *  fLastReleaseCloses  BOOL indicating if the last call to this 
 *                      function should close the object. 
 * 
 * Return Value: 
 *  DWORD           The number of remaining connection counts on 
 *                  the object, used for debugging purposes only. 
 */ 
 
STDMETHODIMP_(DWORD) CKoala::ReleaseConnection(DWORD dwConn 
    , DWORD dwReserved, BOOL fLastReleaseCloses) 
    { 
    DWORD       dwRet; 
    TCHAR       szTemp[80]; 
 
    if (EXTCONN_STRONG & dwConn) 
        { 
        /* 
         * Note:  We don't need to close ourselves when the last 
         * strong lock is removed; we're just implementing this 
         * interface for demonstration. 
         */ 
 
        dwRet=--m_cStrong; 
        wsprintf(szTemp 
            , TEXT("ReleaseConnection cStrong=%lu"), m_cStrong); 
        } 
 
   #ifdef WIN32 
    if (EXTCONN_WEAK & dwConn) 
        { 
        dwRet=--m_cWeak; 
        wsprintf(szTemp 
            , TEXT("ReleaseConnection cWeak=%lu"), m_cWeak); 
        } 
   #endif 
 
   #ifndef WIN32 
    ODS(szTemp); 
   #else 
    MessageBox(NULL, szTemp 
        , TEXT("EKoala3: CKoala::IExternalConnection"), MB_OK); 
   #endif 
 
    return dwRet; 
    } 
 
 
 
 
///IPersist implementation 
 
/* 
 * CImpIPersist:CImpIPersist 
 * CImpIPersist::~CImpIPersist 
 * 
 * Constructor Parameters: 
 *  pObj            PCKoala pointing to the object we live in. 
 *  pUnkOuter       LPUNKNOWN of the controlling unknown. 
 */ 
 
CImpIPersist::CImpIPersist(PCKoala pObj, LPUNKNOWN pUnkOuter) 
    { 
    m_cRef=0; 
    m_pObj=pObj; 
    m_pUnkOuter=pUnkOuter; 
    return; 
    } 
 
CImpIPersist::~CImpIPersist(void) 
    { 
    return; 
    } 
 
 
 
/* 
 * CImpIPersist::QueryInterface 
 * CImpIPersist::AddRef 
 * CImpIPersist::Release 
 * 
 * Purpose: 
 *  Delegating IUnknown members for CImpIPersist. 
 */ 
 
STDMETHODIMP CImpIPersist::QueryInterface(REFIID riid 
    , LPVOID *ppv) 
    { 
    return m_pUnkOuter->QueryInterface(riid, ppv); 
    } 
 
STDMETHODIMP_(ULONG) CImpIPersist::AddRef(void) 
    { 
    ++m_cRef; 
    return m_pUnkOuter->AddRef(); 
    } 
 
STDMETHODIMP_(ULONG) CImpIPersist::Release(void) 
    { 
    --m_cRef; 
    return m_pUnkOuter->Release(); 
    } 
 
 
 
/* 
 * CImpIPersist::GetClassID 
 * 
 * Purpose: 
 *  Returns the CLSID of the object represented by this interface. 
 * 
 * Parameters: 
 *  pClsID          LPCLSID in which to store our CLSID. 
 */ 
 
STDMETHODIMP CImpIPersist::GetClassID(LPCLSID pClsID) 
    { 
    *pClsID=CLSID_Koala; 
    return NOERROR; 
    } 
 
//End CHAPTER6MOD