home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap14 / cosmo / autobase.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  10.5 KB  |  448 lines

  1. /*
  2.  * AUTOBASE.CPP
  3.  * Cosmo Chapter 14
  4.  *
  5.  * Base object for Cosmo's OLE Automation support.  This class
  6.  * provides the implementation of IDispatch as well as the code
  7.  * that loads the appropriate type information.  This leaves
  8.  * each specific object to implement it's specific interface and
  9.  * little else.
  10.  *
  11.  * Copyright (c)1993-1995 Microsoft Corporation, All Right Reserved.
  12.  *
  13.  * Kraig Brockschmidt, Microsoft
  14.  * Internet  :  kraigb@microsoft.com
  15.  * Compuserve:  INTERNET>kraigb@microsoft.com
  16.  */
  17.  
  18.  
  19. #include "cosmo.h"
  20.  
  21.  
  22. /*
  23.  * CAutoBase::CAutoBase
  24.  * CAutoBase::~CAutoBase
  25.  *
  26.  * Constructor Parameters:
  27.  *  pv              void * to the frame or document object that
  28.  *                  derived classes will use to access the functions
  29.  *                  they need to implemenet their interface.
  30.  *  hInst           HINSTANCE of the application (for loading
  31.  *                  resources)
  32.  *  riid            REFIID of the interface that this object
  33.  *                  should expose.
  34.  *  rdiid           REFIID of the dispinterface that this
  35.  *                  object should expose.
  36.  *  pfnDestroy      PFNDESTROYED to call when the object
  37.  *                  is destroyed.
  38.  */
  39.  
  40. CAutoBase::CAutoBase(void *pv, HINSTANCE hInst, REFIID riid
  41.     , REFIID rdiid, PFNDESTROYED pfnDestroy)
  42.     {
  43.     m_cRef=0L;
  44.     m_pfnDestroy=pfnDestroy;
  45.  
  46.     m_pObj=pv;
  47.     m_hInst=hInst;
  48.  
  49.     m_iid=riid;
  50.     m_diid=rdiid;
  51.  
  52.     m_pImpIDispatch=NULL;
  53.     m_pImpIExtConn=NULL;
  54.     return;
  55.     }
  56.  
  57.  
  58. CAutoBase::~CAutoBase(void)
  59.     {
  60.     DeleteInterfaceImp(m_pImpIExtConn);
  61.     DeleteInterfaceImp(m_pImpIDispatch);
  62.     return;
  63.     }
  64.  
  65.  
  66. /*
  67.  * CAutoBase::Init
  68.  *
  69.  * Purpose:
  70.  *  Performs any intiailization of CAutoBase that's prone to failure
  71.  *  that we also use internally before exposing the object outside.
  72.  *
  73.  * Parameters:
  74.  *  fExtConn        BOOL indicating if we care about external
  75.  *                  connections for shutdown.
  76.  *
  77.  * Return Value:
  78.  *  BOOL            TRUE if the function is successful,
  79.  *                  FALSE otherwise.
  80.  */
  81.  
  82. BOOL CAutoBase::Init(BOOL fExtConn)
  83.     {
  84.     //The derived class has to supply the IUnknown implementation
  85.     m_pImpIDispatch=new CImpIDispatch(this
  86.         , (IUnknown *)VTableInterface());
  87.  
  88.     if (NULL==m_pImpIDispatch)
  89.         return FALSE;
  90.  
  91.     if (fExtConn)
  92.         {
  93.         m_pImpIExtConn=new CImpIExtConn
  94.             ((IUnknown *)VTableInterface());
  95.  
  96.         if (NULL==m_pImpIExtConn)
  97.             return FALSE;
  98.         }
  99.  
  100.     return TRUE;
  101.     }
  102.  
  103.  
  104.  
  105. //IDispatch interface implementation
  106.  
  107. /*
  108.  * CImpIDispatch::CImpIDispatch
  109.  * CImpIDispatch::~CImpIDispatch
  110.  *
  111.  * Parameters (Constructor):
  112.  *  pObj            PCAutoBase to the containing object.
  113.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  114.  */
  115.  
  116. CImpIDispatch::CImpIDispatch(PCAutoBase pObj, LPUNKNOWN pUnkOuter)
  117.     {
  118.     m_cRef=0;
  119.     m_pObj=pObj;
  120.     m_pUnkOuter=pUnkOuter;
  121.     m_pITypeInfo=NULL;
  122.     return;
  123.     }
  124.  
  125. CImpIDispatch::~CImpIDispatch(void)
  126.     {
  127.     ReleaseInterface(m_pITypeInfo);
  128.     return;
  129.     }
  130.  
  131.  
  132.  
  133. /*
  134.  * CImpIDispatch::QueryInterface
  135.  * CImpIDispatch::AddRef
  136.  * CImpIDispatch::Release
  137.  *
  138.  * Purpose:
  139.  *  IUnknown members for CImpIDispatch object.
  140.  */
  141.  
  142. STDMETHODIMP CImpIDispatch::QueryInterface(REFIID riid, PPVOID ppv)
  143.     {
  144.     return m_pUnkOuter->QueryInterface(riid, ppv);
  145.     }
  146.  
  147.  
  148. STDMETHODIMP_(ULONG) CImpIDispatch::AddRef(void)
  149.     {
  150.     ++m_cRef;
  151.     return m_pUnkOuter->AddRef();
  152.     }
  153.  
  154. STDMETHODIMP_(ULONG) CImpIDispatch::Release(void)
  155.     {
  156.     --m_cRef;
  157.     return m_pUnkOuter->Release();
  158.     }
  159.  
  160.  
  161.  
  162. /*
  163.  * CImpIDispatch::GetTypeInfoCount
  164.  * CImpIDispatch::GetTypeInfo
  165.  */
  166.  
  167. STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)
  168.     {
  169.     //We implement GetTypeInfo so return 1
  170.     *pctInfo=1;
  171.     return NOERROR;
  172.     }
  173.  
  174. STDMETHODIMP CImpIDispatch::GetTypeInfo(UINT itInfo, LCID lcid
  175.     , ITypeInfo **ppITypeInfo)
  176.     {
  177.     HRESULT     hr;
  178.     ITypeLib   *pITypeLib;
  179.     ITypeInfo **ppITI=NULL;
  180.  
  181.     if (0!=itInfo)
  182.         return ResultFromScode(TYPE_E_ELEMENTNOTFOUND);
  183.  
  184.     if (NULL==ppITypeInfo)
  185.         return ResultFromScode(E_POINTER);
  186.  
  187.     *ppITypeInfo=NULL;
  188.  
  189.     /*
  190.      * This switch statement is nicely extensible for other
  191.      * languages and other m_pITypeInfo variables (such as it
  192.      * was used in Beeper #2 (see ..\beeper2\beeper.cpp)
  193.      */
  194.     switch (PRIMARYLANGID(lcid))
  195.         {
  196.         case LANG_NEUTRAL:
  197.         case LANG_ENGLISH:
  198.             ppITI=&m_pITypeInfo;
  199.             break;
  200.  
  201.         default:
  202.             return ResultFromScode(DISP_E_UNKNOWNLCID);
  203.         }
  204.  
  205.     //Load a type lib if we don't have the information already.
  206.     if (NULL==*ppITI)
  207.         {
  208.         hr=LoadRegTypeLib(LIBID_CosmoTypeLibrary, 1, 0
  209.             , PRIMARYLANGID(lcid), &pITypeLib);
  210.  
  211.         /*
  212.          * If LoadRegTypeLib fails, try loading directly from
  213.          * our module with LoadTypeLib.
  214.          */
  215.         if (FAILED(hr))
  216.             {
  217.             const int   cch=512;
  218.             TCHAR       szModule[cch];
  219.  
  220.             GetModuleFileName(m_pObj->m_hInst, szModule, cch);
  221.  
  222.             switch (PRIMARYLANGID(lcid))
  223.                 {
  224.                 case LANG_NEUTRAL:
  225.                 case LANG_ENGLISH:
  226.                    #ifdef WIN32ANSI
  227.                     OLECHAR szTemp[512];
  228.                     MultiByteToWideChar(CP_ACP, 0, szModule, -1, szTemp, 512);
  229.                     hr=LoadTypeLib(szTemp, &pITypeLib);
  230.                    #else
  231.                     hr=LoadTypeLib(szModule, &pITypeLib);
  232.                    #endif
  233.                     break;
  234.  
  235.                 /*
  236.                  * Easily extensible with additional languages.
  237.                  * Use LoadTypeLibFromResource or specify
  238.                  * separate .TLB files instead of the module name.
  239.                  * Be sure to use your DIR registry key to find
  240.                  * the right path.
  241.                  */
  242.                 }
  243.             }
  244.  
  245.         if (FAILED(hr))
  246.             return hr;
  247.  
  248.         //Got the type lib, get type info for the interface we want
  249.         hr=pITypeLib->GetTypeInfoOfGuid(m_pObj->m_iid, ppITI);
  250.         pITypeLib->Release();
  251.  
  252.         if (FAILED(hr))
  253.             return hr;
  254.         }
  255.  
  256.     //Ref on ITypeInfo holds type library in memory
  257.     (*ppITI)->AddRef();
  258.     *ppITypeInfo=*ppITI;
  259.     return NOERROR;
  260.     }
  261.  
  262.  
  263.  
  264. /*
  265.  * CImpIDispatch::GetIDsOfNames
  266.  * CImpIDispatch::Invoke
  267.  */
  268.  
  269. STDMETHODIMP CImpIDispatch::GetIDsOfNames(REFIID riid
  270.     , OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID)
  271.     {
  272.     HRESULT     hr;
  273.     ITypeInfo  *pTI;
  274.  
  275.     if (IID_NULL!=riid)
  276.         return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  277.  
  278.     hr=GetTypeInfo(0, lcid, &pTI);
  279.  
  280.     if (SUCCEEDED(hr))
  281.         {
  282.         hr=DispGetIDsOfNames(pTI, rgszNames, cNames, rgDispID);
  283.         pTI->Release();
  284.         }
  285.  
  286.     return hr;
  287.     }
  288.  
  289. STDMETHODIMP CImpIDispatch::Invoke(DISPID dispID, REFIID riid
  290.     , LCID lcid, unsigned short wFlags, DISPPARAMS *pDispParams
  291.     , VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
  292.     {
  293.     HRESULT     hr;
  294.     ITypeInfo  *pTI;
  295.  
  296.     if (IID_NULL!=riid)
  297.         return ResultFromScode(DISP_E_UNKNOWNINTERFACE);
  298.  
  299.     //Get the ITypeInfo for lcid
  300.     hr=GetTypeInfo(0, lcid, &pTI);
  301.  
  302.     if (FAILED(hr))
  303.         return hr;
  304.  
  305.     //Note:  this sample doesn't do anything with exceptions.
  306.  
  307.     //The VTableInterface function gets us the right pointer
  308.     hr=pTI->Invoke(m_pObj->VTableInterface(), dispID, wFlags
  309.         , pDispParams, pVarResult, pExcepInfo, puArgErr);
  310.  
  311.     pTI->Release();
  312.     return hr;
  313.     }
  314.  
  315.  
  316.  
  317.  
  318. //IExternalConnection implementation
  319.  
  320. /*
  321.  * CImpIExtConn::CImpIExtConn
  322.  * CImpIExtConn::~CImpIExtConn
  323.  *
  324.  * Parameters (Constructor):
  325.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  326.  */
  327.  
  328. CImpIExtConn::CImpIExtConn(LPUNKNOWN pUnkOuter)
  329.     {
  330.     m_cRef=0;
  331.     m_pUnkOuter=pUnkOuter;
  332.     m_cStrong=0;
  333.     return;
  334.     }
  335.  
  336. CImpIExtConn::~CImpIExtConn(void)
  337.     {
  338.     return;
  339.     }
  340.  
  341.  
  342.  
  343. /*
  344.  * CImpIExtConn::QueryInterface
  345.  * CImpIExtConn::AddRef
  346.  * CImpIExtConn::Release
  347.  *
  348.  * Purpose:
  349.  *  Delegating IUnknown members for CImpIExtConn.
  350.  */
  351.  
  352. STDMETHODIMP CImpIExtConn::QueryInterface(REFIID riid
  353.     , LPVOID *ppv)
  354.     {
  355.     return m_pUnkOuter->QueryInterface(riid, ppv);
  356.     }
  357.  
  358.  
  359. STDMETHODIMP_(ULONG) CImpIExtConn::AddRef(void)
  360.     {
  361.     ++m_cRef;
  362.     return m_pUnkOuter->AddRef();
  363.     }
  364.  
  365. STDMETHODIMP_(ULONG) CImpIExtConn::Release(void)
  366.     {
  367.     --m_cRef;
  368.     return m_pUnkOuter->Release();
  369.     }
  370.  
  371.  
  372.  
  373.  
  374. /*
  375.  * CImpIExtConn::AddConnection
  376.  *
  377.  * Purpose:
  378.  *  Informs the object that a connection has been made to it.  We
  379.  *  count only strong references.
  380.  *
  381.  * Parameters:
  382.  *  dwConn          DWORD identifying the type of connection, taken
  383.  *                  from the EXTCONN enumeration.
  384.  *  dwReserved      DWORD reserved.  This is used inside OLE and
  385.  *                  should not be validated.
  386.  *
  387.  * Return Value:
  388.  *  DWORD           The number of connection counts on the
  389.  *                  object, used for debugging purposes only.
  390.  */
  391.  
  392. STDMETHODIMP_(DWORD) CImpIExtConn::AddConnection
  393.     (DWORD dwConn, DWORD dwReserved)
  394.     {
  395.     if (EXTCONN_STRONG==dwConn)
  396.         {
  397.         m_cStrong++;
  398.         return m_cStrong;
  399.         }
  400.  
  401.     return 0L;
  402.     }
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409. /*
  410.  * CImpIExtConn::ReleaseConnection
  411.  *
  412.  * Purpose:
  413.  *  Informs an object that a connection has been taken away from
  414.  *  it in which case the object may need to shut down.
  415.  *
  416.  * Parameters:
  417.  *  dwConn              DWORD identifying the type of connection,
  418.  *                      taken from the EXTCONN enumeration.
  419.  *  dwReserved          DWORD reserved.  This is used inside OLE and
  420.  *                      should not be validated.
  421.  *  fLastReleaseCloses  BOOL indicating if the last call to this
  422.  *                      function should close the object.
  423.  *
  424.  * Return Value:
  425.  *  DWORD           The number of remaining connection counts on
  426.  *                  the object, used for debugging purposes only.
  427.  */
  428.  
  429. STDMETHODIMP_(DWORD) CImpIExtConn::ReleaseConnection
  430.     (DWORD dwConn, DWORD dwReserved, BOOL fLastReleaseCloses)
  431.     {
  432.     DWORD       dw=0L;
  433.  
  434.     if (EXTCONN_STRONG==dwConn)
  435.         {
  436.         dw=--m_cStrong;
  437.  
  438.         /*
  439.          * Note that in the way we're using this interface we
  440.          * don't care about fLastReleaseCloses.
  441.          */
  442.         if (0L==m_cStrong)
  443.             m_pUnkOuter->Release();     //Closes app or doc
  444.         }
  445.  
  446.     return dw;
  447.     }
  448.