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 / chap22 / patron / iolecont.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  12KB  |  486 lines

  1. /*
  2.  * IOLECONT.CPP
  3.  * Patron Chapter 22
  4.  *
  5.  * Implementation of the IOleItemContainer interface for Patron's
  6.  * CPage and CPatronDoc alike, using the constructor parameter fDoc
  7.  * to differentiate.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15.  
  16.  
  17. #include <stdlib.h>
  18. #include "patron.h"
  19.  
  20.  
  21. /*
  22.  * CImpIOleItemContainer::CImpIOleItemContainer
  23.  * CImpIOleItemContainer::~CImpIOleItemContainer
  24.  *
  25.  * Parameters (Constructor):
  26.  *  pObj            LPVOID of the page or pages.
  27.  *  pUnkOuter       LPUNKNOWN to which we delegate.
  28.  *  fDoc            BOOL indicating if we're in CPatronDoc or CPage
  29.  */
  30.  
  31. CImpIOleItemContainer::CImpIOleItemContainer(LPVOID pObj
  32.     , LPUNKNOWN pUnkOuter, BOOL fDoc)
  33.     {
  34.     m_cRef=0;
  35.     m_fDoc=fDoc;
  36.  
  37.     if (fDoc)
  38.         {
  39.         m_pDoc=(PCPatronDoc)pObj;
  40.         m_pPage=NULL;
  41.         }
  42.     else
  43.         {
  44.         m_pDoc=NULL;
  45.         m_pPage=(PCPage)pObj;
  46.         }
  47.  
  48.     m_pUnkOuter=pUnkOuter;
  49.     return;
  50.     }
  51.  
  52. CImpIOleItemContainer::~CImpIOleItemContainer(void)
  53.     {
  54.     return;
  55.     }
  56.  
  57.  
  58.  
  59.  
  60. /*
  61.  * CImpIOleItemContainer::QueryInterface
  62.  * CImpIOleItemContainer::AddRef
  63.  * CImpIOleItemContainer::Release
  64.  *
  65.  * Purpose:
  66.  *  IUnknown members for CImpIOleItemContainer object.
  67.  */
  68.  
  69. STDMETHODIMP CImpIOleItemContainer::QueryInterface(REFIID riid
  70.     , PPVOID ppv)
  71.     {
  72.     return m_pUnkOuter->QueryInterface(riid, ppv);
  73.     }
  74.  
  75.  
  76. STDMETHODIMP_(ULONG) CImpIOleItemContainer::AddRef(void)
  77.     {
  78.     ++m_cRef;
  79.     return m_pUnkOuter->AddRef();
  80.     }
  81.  
  82. STDMETHODIMP_(ULONG) CImpIOleItemContainer::Release(void)
  83.     {
  84.     --m_cRef;
  85.     return m_pUnkOuter->Release();
  86.     }
  87.  
  88.  
  89.  
  90. /*
  91.  * CImpIOleItemContainer::ParseDisplayName
  92.  *
  93.  * Purpose:
  94.  *  Inherited member of IParseDisplayName that takes a string name
  95.  *  and turns out a moniker for it.
  96.  *
  97.  * Parameters:
  98.  *  pbc             LPBC to the binding context
  99.  *  pszName         LPOLESTR to the name to parse.
  100.  *  pchEaten        ULONG * into which to store how many
  101.  *                  characters we scanned in the display name.
  102.  *  ppmk            LPMONIKER * in which to return the moniker.
  103.  *
  104.  * Return Value:
  105.  *  HRESULT         NOERROR or a general error value.
  106.  */
  107.  
  108. STDMETHODIMP CImpIOleItemContainer::ParseDisplayName(LPBC pbc
  109.     , LPOLESTR pszName, ULONG *pchEaten, LPMONIKER *ppmk)
  110.     {
  111.     OLECHAR     ch;
  112.     ULONG       chEaten=0;
  113.     TCHAR       szName[256];
  114.     TCHAR       szComp[15];
  115.     LPTSTR      psz;
  116.     UINT        cch;
  117.  
  118.     *ppmk=NULL;
  119.     *pchEaten=0;
  120.  
  121.     /*
  122.      * All we have to look for is the string between the !
  123.      * delimeters (or a null terminator).  pszName should be pointing
  124.      * to a !, so skip it and scan the string for a ! or 0,
  125.      * then pass the result to CreateItemMoniker.
  126.      */
  127.  
  128.     psz=szName;
  129.  
  130.     ch=*pszName++;
  131.     chEaten++;
  132.  
  133.     if ((OLECHAR)'!'!=ch)
  134.         return ResultFromScode(MK_E_SYNTAX);
  135.  
  136.     ch=*pszName++;
  137.  
  138.     while ((OLECHAR)0!=ch && (OLECHAR)'!' !=ch)
  139.         {
  140.         *psz++=(TCHAR)ch;
  141.         chEaten++;
  142.         ch=*pszName++;
  143.         }
  144.  
  145.     *psz=(TCHAR)0;
  146.  
  147.     /*
  148.      * Syntax check.  If we're the DOcument object, check for
  149.      * "Page n" at the beginning of the string.  Otherwise check
  150.      * for "Tenant n".
  151.      */
  152.     lstrcpy(szComp, m_fDoc ? TEXT("Page ") : TEXT("Tenant "));
  153.  
  154.     //Does szName start with szComp?
  155.     cch=lstrlen(szComp);
  156.  
  157.     if (0!=_tcsncicmp(szName, szComp, cch))
  158.         {
  159.         *pchEaten=1;    //Parsed ! at least
  160.         return ResultFromScode(MK_E_SYNTAX);
  161.         }
  162.  
  163.     //Check for a number in szName
  164.     if ((TCHAR)'0' != szName[cch])
  165.         {
  166.         if (0==_ttoi(szName+cch))
  167.             {
  168.             *pchEaten=cch;  //Got past name
  169.             return ResultFromScode(MK_E_SYNTAX);
  170.             }
  171.         }
  172.  
  173.     *pchEaten=chEaten;
  174.    #ifdef WIN32ANSI
  175.     //Use the ANSI version here since szName is ANSI
  176.     return INOLE_CreateItemMoniker(TEXT("!"), szName, ppmk);
  177.    #else
  178.     return CreateItemMoniker(OLETEXT("!"), szName, ppmk);
  179.    #endif
  180.     }
  181.  
  182.  
  183.  
  184.  
  185. /*
  186.  * CImpIOleItemContainer::EnumObjects
  187.  *
  188.  * Purpose:
  189.  *  Creates and returns an IEnumUnknown object that allows the
  190.  *  caller to walk through the objects in this continer thing.
  191.  *
  192.  * Parameters:
  193.  *  dwFlags         DWORD specifying what kind of objects to
  194.  *                  enumerate.
  195.  *  ppEnum          LPENUMUNKNOWN * into which to return the
  196.  *                  enumerator
  197.  *
  198.  * Return Value:
  199.  *  HRESULT         NOERROR or a general error value.
  200.  */
  201.  
  202. STDMETHODIMP CImpIOleItemContainer::EnumObjects(DWORD dwFlags
  203.     , LPENUMUNKNOWN *ppEnum)
  204.     {
  205.     *ppEnum=NULL;
  206.     return ResultFromScode(E_NOTIMPL);
  207.     }
  208.  
  209.  
  210.  
  211.  
  212. /*
  213.  * CImpIOleItemContainer::LockContainer
  214.  *
  215.  * Purpose:
  216.  *  Establishes a lock on the container to prevent it from shutting
  217.  *  down outside of user control.  This is used to control the
  218.  *  lifetime of the container when it's used to update a link to an
  219.  *  embedded object within it.  If we're unlock and the user has not
  220.  *  taken control, we close.
  221.  *
  222.  * Parameters:
  223.  *  fLock           BOOL indicating a lock or unlock.
  224.  *
  225.  * Return Value:
  226.  *  HRESULT         NOERROR or a general error value.
  227.  */
  228.  
  229. STDMETHODIMP CImpIOleItemContainer::LockContainer(BOOL fLock)
  230.     {
  231.     /*
  232.      * This is pretty much the same implementation as
  233.      * IClassFactory::LockServer, and we can use the same lock
  234.      * count to accomplish our goal.
  235.      */
  236.  
  237.     if (fLock)
  238.         g_cLock++;
  239.     else
  240.         {
  241.         g_cLock--;
  242.         g_cObj++;
  243.         ObjectDestroyed();
  244.         }
  245.  
  246.     return NOERROR;
  247.     }
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254. /*
  255.  * CImpIOleItemContainer::GetObject
  256.  *
  257.  * Purpose:
  258.  *  Returns the requested interface pointer on an object in this
  259.  *  container.
  260.  *
  261.  * Parameters:
  262.  *  pszItem         LPOLESTR to the item we must locate.
  263.  *  dwSpeed         DWORD identifying how long the caller is willing
  264.  *                  to wait.
  265.  *  pcb             LPBINDCTX providing the binding context.
  266.  *  riid            REFIID of the interface requested.
  267.  *  ppv             PPVOID into which to return the object.
  268.  *
  269.  * Return Value:
  270.  *  HRESULT         NOERROR or a general error value.
  271.  */
  272.  
  273. STDMETHODIMP CImpIOleItemContainer::GetObject(LPOLESTR pszItem
  274.     , DWORD dwSpeed, LPBINDCTX pbc, REFIID riid, PPVOID ppv)
  275.     {
  276.     DWORD       dw;
  277.     char        szTemp[40];     //ANSI for atol
  278.     HRESULT     hr=ResultFromScode(E_FAIL);
  279.     PCPage      pPage;
  280.     PCTenant    pTenant;
  281.     LPUNKNOWN   pObj;
  282.     UINT        i, iCur;
  283.  
  284.     *ppv=NULL;
  285.  
  286.     if (m_fDoc)
  287.         {
  288.         /*
  289.          * The item name should be "Page n", so we'll do it the
  290.          * easy way:  call atol on pszItem+5 (we always know that
  291.          * we'll have "Page " there since we put it there (see
  292.          * CPage::GetStorageName).
  293.          */
  294.  
  295.         UNICODETOANSI((pszItem+5), szTemp, sizeof(szTemp));
  296.         dw=atol(szTemp);
  297.  
  298.         i=m_pDoc->m_pPG->IPageGetFromID(dw, &pPage, FALSE);
  299.  
  300.         if (NOVALUE==i)
  301.             return hr;
  302.  
  303.         /*
  304.          * If we're asked for immediate speed, only do this if the
  305.          * page is already current, i.e. everything is loaded.
  306.          */
  307.         iCur=m_pDoc->m_pPG->CurPageGet();
  308.  
  309.         if (BINDSPEED_IMMEDIATE==dwSpeed && iCur!=i)
  310.             return ResultFromScode(MK_E_EXCEEDEDDEADLINE);
  311.  
  312.         m_pDoc->m_pPG->CurPageSet(i);
  313.  
  314.         //This will have changed to be the current page now.
  315.         if (NULL!=m_pDoc->m_pPG->m_pPageCur)
  316.             hr=m_pDoc->m_pPG->m_pPageCur->QueryInterface(riid, ppv);
  317.         }
  318.     else
  319.         {
  320.         if (TenantFromName(pszItem, &pTenant))
  321.             {
  322.             pTenant->ObjectGet(&pObj);
  323.  
  324.             /*
  325.              * If we're asked for immediate or moderate, only work
  326.              * if the object is already running.
  327.              */
  328.             hr=IsRunning(pszItem);  //This is the function below
  329.  
  330.             if ((BINDSPEED_IMMEDIATE==dwSpeed
  331.                 || BINDSPEED_MODERATE==dwSpeed) && NOERROR!=hr)
  332.                 hr=ResultFromScode(MK_E_EXCEEDEDDEADLINE);
  333.             else
  334.                 {
  335.                 //IMPORTANT:  Make sure this object is running first
  336.                 OleRun(pObj);
  337.                 hr=pObj->QueryInterface(riid, ppv);
  338.                 }
  339.  
  340.             pObj->Release();
  341.             }
  342.         else
  343.             hr=ResultFromScode(MK_E_NOOBJECT);
  344.         }
  345.  
  346.     return hr;
  347.     }
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354. /*
  355.  * CImpIOleItemContainer::GetObjectStorage
  356.  *
  357.  * Purpose:
  358.  *  Similar to get Object in that we have to locate the object
  359.  *  described by a given name, but instead of returning any old
  360.  *  interface we return a storage element.
  361.  *
  362.  * Parameters:
  363.  *  pszItem         LPOLESTR to the item we must locate.
  364.  *  pcb             LPBINDCTX providing the binding context.
  365.  *  riid            REFIID of the interface requested.  Usually
  366.  *                  IStorage or IStream.
  367.  *  ppv             PPVOID into which to return the object.
  368.  *
  369.  * Return Value:
  370.  *  HRESULT         NOERROR or a general error value.
  371.  */
  372.  
  373. STDMETHODIMP CImpIOleItemContainer::GetObjectStorage(LPOLESTR pszItem
  374.     , LPBINDCTX pbc, REFIID riid, PPVOID ppv)
  375.     {
  376.     PCTenant    pTenant;
  377.  
  378.     *ppv=NULL;
  379.  
  380.     if (m_fDoc)
  381.         return ResultFromScode(E_NOTIMPL);
  382.  
  383.     //Can only handle IStorage.
  384.     if (IID_IStorage!=riid)
  385.         return ResultFromScode(E_NOINTERFACE);
  386.  
  387.     if (TenantFromName(pszItem, &pTenant))
  388.         pTenant->StorageGet((LPSTORAGE *)ppv);
  389.  
  390.     return (NULL!=*ppv) ? NOERROR : ResultFromScode(E_FAIL);
  391.     }
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398. /*
  399.  * CImpIOleItemContainer::IsRunning
  400.  *
  401.  * Purpose:
  402.  *  Answers if the object under the given name is currently running.
  403.  *
  404.  * Parameters:
  405.  *  pszItem         LPOLESTR of the item to check
  406.  *
  407.  * Return Value:
  408.  *  HRESULT         NOERROR if the object is running, S_FALSE
  409.  *                  otherwise.  Possibly MK_E_NOOBJECT if the name
  410.  *                  is bogus.
  411.  */
  412.  
  413. STDMETHODIMP CImpIOleItemContainer::IsRunning(LPOLESTR pszItem)
  414.     {
  415.     HRESULT     hr;
  416.     PCTenant    pTenant;
  417.     LPUNKNOWN   pObj;
  418.     LPOLEOBJECT pIOleObject;
  419.  
  420.     /*
  421.      * If this is the document's container interface, the object
  422.      * is a page and the page is always running.
  423.      */
  424.     if (m_fDoc)
  425.         return NOERROR;
  426.     else
  427.         {
  428.         if (TenantFromName(pszItem, &pTenant))
  429.             {
  430.             //Ask the actual object if its running.
  431.             pTenant->ObjectGet(&pObj);
  432.             hr=pObj->QueryInterface(IID_IOleObject
  433.                 , (PPVOID)&pIOleObject);
  434.             pObj->Release();
  435.  
  436.             if (SUCCEEDED(hr))
  437.                 {
  438.                 hr=(OleIsRunning(pIOleObject))
  439.                     ? NOERROR : ResultFromScode(S_FALSE);
  440.                 pIOleObject->Release();
  441.                 }
  442.             }
  443.         else
  444.             hr=ResultFromScode(MK_E_NOOBJECT);
  445.         }
  446.  
  447.     return hr;
  448.     }
  449.  
  450.  
  451.  
  452.  
  453. /*
  454.  * CImpIOleItemContainer::TenantFromName
  455.  * (Private)
  456.  *
  457.  * Purpose:
  458.  *  This function which is NOT part of the interface retrieves
  459.  *  a tenant pointer from a tenant name.
  460.  *
  461.  * Parameters:
  462.  *  pszItem         LPOLESTR of the tenant to locate.
  463.  *  ppTenant        PCTenant * in which to return the pointer.
  464.  *
  465.  * Return Value:
  466.  *  BOOL            TRUE if successful, FALSE otherwise.
  467.  */
  468.  
  469. BOOL CImpIOleItemContainer::TenantFromName(LPOLESTR pszItem
  470.     , PCTenant *ppTenant)
  471.     {
  472.     DWORD       dw;
  473.     char        szTemp[40];     //ANSI for atol
  474.  
  475.     if (m_fDoc)
  476.         return FALSE;
  477.  
  478.     //The item name should be "Tenant xxxx", so use pszItem+7.
  479.     UNICODETOANSI((pszItem+7), szTemp, sizeof(szTemp));
  480.     dw=atol(szTemp);
  481.  
  482.     *ppTenant=NULL;
  483.  
  484.     return m_pPage->TenantGetFromID(dw, ppTenant, FALSE);
  485.     }
  486.