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 / chap21 / patron / tenant.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  55.6 KB  |  2,279 lines

  1. /*
  2.  * TENANT.CPP
  3.  * Patron Chapter 21
  4.  *
  5.  * Implementation of the CTentant class which holds information
  6.  * for a single object on a page.  It maintains position, references
  7.  * to data, and a storage.
  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 "patron.h"
  18.  
  19.  
  20. /*
  21.  * CTenant::CTenant
  22.  * CTenant::~CTenant
  23.  *
  24.  * Constructor Parameters:
  25.  *  dwID            DWORD identifier for this page.
  26.  *  hWnd            HWND of the pages window.
  27.  *  pPG             PCPages to the parent structure.
  28.  */
  29.  
  30. CTenant::CTenant(DWORD dwID, HWND hWnd, PCPages pPG)
  31.     {
  32.     m_hWnd=hWnd;
  33.     m_dwID=dwID;
  34.  
  35.     m_fInitialized=0;
  36.     m_pIStorage=NULL;
  37.     m_cOpens=0;
  38.  
  39.     m_pObj=NULL;
  40.     m_pPG =pPG;
  41.     m_clsID=CLSID_NULL;
  42.     m_fSetExtent=FALSE;
  43.  
  44.     m_cRef=0;
  45.     m_pIOleObject=NULL;
  46.     m_pIViewObject2=NULL;
  47.     m_grfMisc=0;
  48.  
  49.     m_pImpIOleClientSite=NULL;
  50.     m_pImpIAdviseSink=NULL;
  51.  
  52.     m_fRepaintEnabled=TRUE;
  53.     m_pmkFile=NULL;
  54.     m_fLinkAvail=TRUE;          //Checked on Load
  55.  
  56.     //CHAPTER21MOD
  57.     m_pmk=NULL;
  58.     //End CHAPTER21MOD
  59.     return;
  60.     }
  61.  
  62.  
  63. CTenant::~CTenant(void)
  64.     {
  65.     //CHAPTER21MOD
  66.     ReleaseInterface(m_pmk);
  67.     //End CHAPTER21MOD
  68.  
  69.     ReleaseInterface(m_pmkFile);
  70.  
  71.     //Object pointers cleaned up in Close.
  72.  
  73.     DeleteInterfaceImp(m_pImpIAdviseSink);
  74.     DeleteInterfaceImp(m_pImpIOleClientSite);
  75.     return;
  76.     }
  77.  
  78.  
  79.  
  80.  
  81. /*
  82.  * CTenant::QueryInterface
  83.  * CTenant::AddRef
  84.  * CTenant::Release
  85.  *
  86.  * Purpose:
  87.  *  IUnknown members for CTenant object.
  88.  */
  89.  
  90. STDMETHODIMP CTenant::QueryInterface(REFIID riid, PPVOID ppv)
  91.     {
  92.     *ppv=NULL;
  93.  
  94.     if (IID_IUnknown==riid)
  95.         *ppv=this;
  96.  
  97.     if (IID_IOleClientSite==riid)
  98.         *ppv=m_pImpIOleClientSite;
  99.  
  100.     if (IID_IAdviseSink==riid)
  101.         *ppv=m_pImpIAdviseSink;
  102.  
  103.     if (NULL!=*ppv)
  104.         {
  105.         ((LPUNKNOWN)*ppv)->AddRef();
  106.         return NOERROR;
  107.         }
  108.  
  109.     return ResultFromScode(E_NOINTERFACE);
  110.     }
  111.  
  112.  
  113. STDMETHODIMP_(ULONG) CTenant::AddRef(void)
  114.     {
  115.     return ++m_cRef;
  116.     }
  117.  
  118. STDMETHODIMP_(ULONG) CTenant::Release(void)
  119.     {
  120.     if (0!=--m_cRef)
  121.         return m_cRef;
  122.  
  123.     delete this;
  124.     return 0;
  125.     }
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132. /*
  133.  * CTenant::GetID
  134.  *
  135.  * Return Value:
  136.  *  DWORD           dwID field in this tenant.
  137.  */
  138.  
  139. DWORD CTenant::GetID(void)
  140.     {
  141.     return m_dwID;
  142.     }
  143.  
  144.  
  145.  
  146. /*
  147.  * CTenant::GetStorageName
  148.  *
  149.  * Parameters:
  150.  *  pszName         LPOLESTR to a buffer in which to store the storage
  151.  *                  name for this tenant.
  152.  *
  153.  * Return Value:
  154.  *  UINT            Number of characters stored.
  155.  */
  156.  
  157. UINT CTenant::GetStorageName(LPOLESTR pszName)
  158.     {
  159.    #ifdef WIN32ANSI
  160.     char        szTemp[32];
  161.     UINT        cch;
  162.  
  163.     cch=wsprintf(szTemp, "Tenant %lu", m_dwID);
  164.     MultiByteToWideChar(CP_ACP, 0, szTemp, -1, pszName, 32);
  165.     return cch;
  166.    #else
  167.     return wsprintf(pszName, TEXT("Tenant %lu"), m_dwID);
  168.    #endif
  169.     }
  170.  
  171.  
  172.  
  173. /*
  174.  * CTenant::StorageGet
  175.  *
  176.  * Purpose:
  177.  *  Returns the IStorage pointer maintained by this tenant,
  178.  *  AddRef'd of course.
  179.  *
  180.  * Parameters:
  181.  *  ppStg           LPSTORAGE * in which to return the pointer.
  182.  *
  183.  * Return Value:
  184.  *  None
  185.  */
  186.  
  187. void CTenant::StorageGet(LPSTORAGE *ppStg)
  188.     {
  189.     if (NULL==ppStg)
  190.         return;
  191.  
  192.     *ppStg=m_pIStorage;
  193.  
  194.     if (NULL!=*ppStg)
  195.         (*ppStg)->AddRef();
  196.  
  197.     return;
  198.     }
  199.  
  200.  
  201.  
  202.  
  203. /*
  204.  * CTenant::Create
  205.  *
  206.  * Purpose:
  207.  *  Creates a new tenant of the given CLSID, which can be either a
  208.  *  static bitmap or metafile or any compound document object.
  209.  *
  210.  * Parameters:
  211.  *  tType           TENANTTYPE to create, either a static metafile,
  212.  *                  bitmap, or some kind of compound document object
  213.  *                  This determines which OleCreate* call we use.
  214.  *  pvType          LPVOID providing the relevant pointer from which
  215.  *                  to create the tenant, depending on iType.
  216.  *  pFE             LPFORMATETC specifying the type of renderings
  217.  *                  to use.
  218.  *  pptl            PPOINTL in which we store offset coordinates.
  219.  *  pszl            LPSIZEL where this object should store its
  220.  *                  lometric extents.
  221.  *  pIStorage       LPSTORAGE of the page we live in.  We have to
  222.  *                  create another storage in this for the tenant.
  223.  *  ppo             PPATRONOBJECT containing placement data.
  224.  *  dwData          DWORD with extra data, sensitive to iType.
  225.  *
  226.  * Return Value:
  227.  *  UINT            A CREATE_* value depending on what we
  228.  *                  actually do.
  229.  */
  230.  
  231. UINT CTenant::Create(TENANTTYPE tType, LPVOID pvType
  232.     , LPFORMATETC pFE, PPOINTL pptl, LPSIZEL pszl
  233.     , LPSTORAGE pIStorage, PPATRONOBJECT ppo, DWORD dwData)
  234.     {
  235.     HRESULT             hr;
  236.     LPUNKNOWN           pObj;
  237.     UINT                uRet=CREATE_GRAPHICONLY;
  238.  
  239.     if (NULL==pvType || NULL==pIStorage)
  240.         return CREATE_FAILED;
  241.  
  242.     //Fail if this is called for an already living tenant.
  243.     if (m_fInitialized)
  244.         return CREATE_FAILED;
  245.  
  246.     m_fInitialized=TRUE;
  247.  
  248.     //Create a new storage for this tenant.
  249.     if (!Open(pIStorage))
  250.         return CREATE_FAILED;
  251.  
  252.     /*
  253.      * Get the placement info if it's here.  We either have a non-
  254.      * NULL PPATRONOBJECT in ppo or we have to use default
  255.      * placement and retrieve the size from the object itself.
  256.      */
  257.     pszl->cx=0;
  258.     pszl->cy=0;
  259.  
  260.     if (NULL!=ppo)
  261.         {
  262.         *pFE=ppo->fe;
  263.         *pptl=ppo->ptl;
  264.         *pszl=ppo->szl;     //Could be 0,0 , so we ask object
  265.  
  266.         uRet=CREATE_PLACEDOBJECT;
  267.         }
  268.  
  269.     hr=ResultFromScode(E_FAIL);
  270.  
  271.     //Now create an object based specifically for the type.
  272.     switch (tType)
  273.         {
  274.         case TENANTTYPE_NULL:
  275.             break;
  276.  
  277.         case TENANTTYPE_STATIC:
  278.             /*
  279.              * We could use OleCreateStaticFromData here which does
  280.              * pretty much what we're doing below.  However, it does
  281.              * not allow us to control whether we paste a bitmap or
  282.              * a metafile--it uses metafile first, bitmap second.
  283.              * For this reason we'll use code developed in Chapter
  284.              * 11's FreeLoader to affect the paste.
  285.              */
  286.             hr=CreateStatic((LPDATAOBJECT)pvType, pFE, &pObj);
  287.             break;
  288.  
  289.         case TENANTTYPE_EMBEDDEDOBJECT:
  290.             hr=OleCreate(*((LPCLSID)pvType), IID_IUnknown
  291.                 , OLERENDER_DRAW, NULL, NULL, m_pIStorage
  292.                 , (PPVOID)&pObj);
  293.             break;
  294.  
  295.         case TENANTTYPE_EMBEDDEDFILE:
  296.             hr=OleCreateFromFile(CLSID_NULL, (LPTSTR)pvType
  297.                 , IID_IUnknown, OLERENDER_DRAW, NULL, NULL
  298.                 , m_pIStorage, (PPVOID)&pObj);
  299.             break;
  300.  
  301.         case TENANTTYPE_EMBEDDEDOBJECTFROMDATA:
  302.             hr=OleCreateFromData((LPDATAOBJECT)pvType, IID_IUnknown
  303.                 , OLERENDER_DRAW, NULL, NULL, m_pIStorage
  304.                 , (PPVOID)&pObj);
  305.             break;
  306.  
  307.         case TENANTTYPE_LINKEDFILE:
  308.             hr=OleCreateLinkToFile((LPTSTR)pvType, IID_IUnknown
  309.                 , OLERENDER_DRAW, NULL, NULL, m_pIStorage
  310.                 , (PPVOID)&pObj);
  311.             break;
  312.  
  313.         case TENANTTYPE_LINKEDOBJECTFROMDATA:
  314.             hr=OleCreateLinkFromData((LPDATAOBJECT)pvType
  315.                 , IID_IUnknown, OLERENDER_DRAW, NULL, NULL
  316.                 , m_pIStorage, (PPVOID)&pObj);
  317.             break;
  318.  
  319.         default:
  320.             break;
  321.         }
  322.  
  323.     //If creation didn't work, get rid of the element Open created.
  324.     if (FAILED(hr))
  325.         {
  326.         Destroy(pIStorage);
  327.         return CREATE_FAILED;
  328.         }
  329.  
  330.     //We don't get the size if PatronObject data was seen already.
  331.     if (!ObjectInitialize(pObj, pFE, dwData))
  332.         {
  333.         Destroy(pIStorage);
  334.         return CREATE_FAILED;
  335.         }
  336.  
  337.     if (0==pszl->cx && 0==pszl->cy)
  338.         {
  339.         SIZEL   szl;
  340.  
  341.         //Try to get the real size of the object, default to 2"*2"
  342.         SETSIZEL((*pszl), 2*LOMETRIC_PER_INCH, 2*LOMETRIC_PER_INCH);
  343.         hr=ResultFromScode(E_FAIL);
  344.  
  345.         //Try IViewObject2 first, then IOleObject as a backup.
  346.         if (NULL!=m_pIViewObject2)
  347.             {
  348.             hr=m_pIViewObject2->GetExtent(m_fe.dwAspect, -1, NULL
  349.                 , &szl);
  350.             }
  351.         else
  352.             {
  353.             if (NULL!=m_pIOleObject)
  354.                 hr=m_pIOleObject->GetExtent(m_fe.dwAspect, &szl);
  355.             }
  356.  
  357.         if (SUCCEEDED(hr))
  358.             {
  359.             //Convert HIMETRIC to our LOMETRIC mapping
  360.             SETSIZEL((*pszl), szl.cx/10, szl.cy/10);
  361.             }
  362.         }
  363.  
  364.     return uRet;
  365.     }
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372. /*
  373.  * CTenant::Load
  374.  *
  375.  * Purpose:
  376.  *  Recreates the object living in this tenant in place of calling
  377.  *  FCreate.  This is used in loading as opposed to new creation.
  378.  *
  379.  * Parameters:
  380.  *  pIStorage       LPSTORAGE of the page we live in.
  381.  *  pti             PTENTANTINFO containing persistent information.
  382.  *                  The ID value in this structure is ignored.
  383.  *
  384.  * Return Value:
  385.  *  BOOL            TRUE if successful, FALSE otherwise.
  386.  */
  387.  
  388. BOOL CTenant::Load(LPSTORAGE pIStorage, PTENANTINFO pti)
  389.     {
  390.     HRESULT         hr;
  391.     LPUNKNOWN       pObj;
  392.     DWORD           dwState=TENANTSTATE_DEFAULT;
  393.  
  394.     if (NULL==pIStorage || NULL==pti)
  395.         return FALSE;
  396.  
  397.     /*
  398.      * If we already initialized once, clean up, releasing
  399.      * everything before we attempt to reload.  This happens
  400.      * when using the Convert Dialog.
  401.      */
  402.     if (m_fInitialized)
  403.         {
  404.         //Preserve all states except open
  405.         dwState=(m_dwState & ~TENANTSTATE_OPEN);
  406.         m_cRef++;   //Prevent accidental closure
  407.  
  408.         //This should release all holds on our IStorage as well.
  409.         if (NULL!=m_pIViewObject2)
  410.             {
  411.             m_pIViewObject2->SetAdvise(m_fe.dwAspect, 0, NULL);
  412.             ReleaseInterface(m_pIViewObject2);
  413.             }
  414.  
  415.         ReleaseInterface(m_pIOleObject);
  416.         ReleaseInterface(m_pObj);
  417.  
  418.         m_pIStorage=NULL;   //We'll have already released this.
  419.         m_cRef--;           //Match safety increment above.
  420.         }
  421.  
  422.     m_fInitialized=TRUE;
  423.  
  424.     //Open the storage for this tenant.
  425.     if (!Open(pIStorage))
  426.         return FALSE;
  427.  
  428.     /*
  429.      * NOTE:  If you do not pass an IOleClientSite to OleLoad
  430.      * it will not automatically reconnect a linked object to
  431.      * the running source via IOleLink::BindIfRunning.  Since
  432.      * we do not pass m_pImpIOleClientSite here, we'll call
  433.      * BindIfRunning ourselves in ObjectInitialize.
  434.      */
  435.     hr=OleLoad(m_pIStorage, IID_IUnknown, NULL, (PPVOID)&pObj);
  436.  
  437.     if (FAILED(hr))
  438.         {
  439.         Destroy(pIStorage);
  440.         return FALSE;
  441.         }
  442.  
  443.     m_fSetExtent=pti->fSetExtent;
  444.     ObjectInitialize(pObj, &pti->fe, NULL);
  445.  
  446.     //Restore the original state before reloading.
  447.     m_dwState=dwState;
  448.  
  449.     RectSet(&pti->rcl, FALSE, FALSE);
  450.     return TRUE;
  451.     }
  452.  
  453.  
  454.  
  455.  
  456. /*
  457.  * CTenant::GetInfo
  458.  *
  459.  * Purpose:
  460.  *  Retrieved a TENANTINFO structure for this tenant.
  461.  *
  462.  * Parameters:
  463.  *  pti             PTENANTINFO structure to fill
  464.  *
  465.  * Return Value:
  466.  *  None
  467.  */
  468.  
  469. void CTenant::GetInfo(PTENANTINFO pti)
  470.     {
  471.     if (NULL!=pti)
  472.         {
  473.         pti->dwID=m_dwID;
  474.         pti->rcl=m_rcl;
  475.         pti->fe=m_fe;
  476.         pti->fSetExtent=m_fSetExtent;
  477.         }
  478.  
  479.     return;
  480.     }
  481.  
  482.  
  483.  
  484.  
  485. /*
  486.  * CTenant::ObjectInitialize
  487.  * (Protected)
  488.  *
  489.  * Purpose:
  490.  *  Performs operations necessary after creating an object or
  491.  *  reloading one from storage.
  492.  *
  493.  * Parameters:
  494.  *  pObj            LPUNKNOWN of the object in this tenant.
  495.  *  pFE             LPFORMATETC describing the graphic here.
  496.  *  dwData          DWORD extra data.  If pFE->dwAspect==
  497.  *                  DVASPECT_ICON then this is the iconic metafile.
  498.  *
  499.  * Return Value:
  500.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  501.  */
  502.  
  503. BOOL CTenant::ObjectInitialize(LPUNKNOWN pObj, LPFORMATETC pFE
  504.     , DWORD dwData)
  505.     {
  506.     HRESULT         hr;
  507.     LPPERSIST       pIPersist=NULL;
  508.     DWORD           dw;
  509.     PCDocument      pDoc;
  510.     TCHAR           szFile[CCHPATHMAX];
  511.     LPOLELINK       pIOleLink=NULL;
  512.  
  513.     if (NULL==pObj || NULL==pFE)
  514.         return FALSE;
  515.  
  516.     m_pObj=pObj;
  517.     m_fe=*pFE;
  518.     m_fe.ptd=NULL;
  519.     m_dwState=TENANTSTATE_DEFAULT;
  520.  
  521.     /*
  522.      * Determine the type:  Static or Embedded.  If Static,
  523.      * this will have CLSID_Picture_Metafile or CLSID_Picture_Dib.
  524.      * Otherwise it's embedded.  Later we'll add a case for links.
  525.      */
  526.     m_tType=TENANTTYPE_EMBEDDEDOBJECT;
  527.  
  528.     if (SUCCEEDED(pObj->QueryInterface(IID_IPersist
  529.         , (PPVOID)&pIPersist)))
  530.         {
  531.         CLSID   clsid=CLSID_NULL;
  532.  
  533.         hr=pIPersist->GetClassID(&clsid);
  534.  
  535.         //If we don't have a CLSID, default to static
  536.         if (FAILED(hr) || CLSID_Picture_Metafile==clsid
  537.             || CLSID_Picture_Dib==clsid)
  538.             m_tType=TENANTTYPE_STATIC;
  539.  
  540.         pIPersist->Release();
  541.         }
  542.  
  543.     //Check if this is a linked object.
  544.     if (SUCCEEDED(pObj->QueryInterface(IID_IOleLink
  545.         , (PPVOID)&pIOleLink)))
  546.         {
  547.         LPMONIKER   pmk;
  548.  
  549.         hr=pIOleLink->GetSourceMoniker(&pmk);
  550.  
  551.         if (FAILED(hr) || NULL==pmk)
  552.             m_tType=TENANTTYPE_STATIC;
  553.         else
  554.             {
  555.             m_tType=TENANTTYPE_LINKEDOBJECT;
  556.             pmk->Release();
  557.  
  558.             //Connect to the object if the source is running.
  559.             pIOleLink->BindIfRunning();
  560.             }
  561.  
  562.         pIOleLink->Release();
  563.         }
  564.  
  565.     m_pIViewObject2=NULL;
  566.     hr=pObj->QueryInterface(IID_IViewObject2
  567.         , (PPVOID)&m_pIViewObject2);
  568.  
  569.     if (FAILED(hr))
  570.         return FALSE;
  571.  
  572.     m_pIViewObject2->SetAdvise(m_fe.dwAspect, 0, m_pImpIAdviseSink);
  573.  
  574.     //We need an IOleObject most of the time, so get one here.
  575.     m_pIOleObject=NULL;
  576.     hr=pObj->QueryInterface(IID_IOleObject
  577.          , (PPVOID)&m_pIOleObject);
  578.  
  579.     /*
  580.      * Follow up object creation with advises and so forth.  If
  581.      * we cannot get IOleObject here, then we know we can't do
  582.      * any IOleObject actions from here on--object is static.
  583.      */
  584.     if (FAILED(hr))
  585.         return TRUE;
  586.  
  587.     /*
  588.      * Get the MiscStatus bits and check for OLEMISC_ONLYICONIC.
  589.      * If set, force dwAspect in m_fe to DVASPECT_ICON so we
  590.      * remember to draw it properly and do extents right.
  591.      */
  592.     m_pIOleObject->GetMiscStatus(m_fe.dwAspect, &m_grfMisc);
  593.  
  594.     if (OLEMISC_ONLYICONIC & m_grfMisc)
  595.         m_fe.dwAspect=DVASPECT_ICON;
  596.  
  597.     /*
  598.      * We could pass m_pImpIOleClientSite in an OleCreate* call, but
  599.      * since this function could be called after OleLoad, we still
  600.      * need to do this here, so it's always done here...
  601.      */
  602.     m_pIOleObject->SetClientSite(m_pImpIOleClientSite);
  603.     m_pIOleObject->Advise(m_pImpIAdviseSink, &dw);
  604.  
  605.     OleSetContainedObject(m_pIOleObject, TRUE);
  606.  
  607.     /*
  608.      * For IOleObject::SetHostNames we need the application name
  609.      * and the document name (which is passed in the object
  610.      * parameter).  The design of Patron doesn't give us nice
  611.      * structured access to the name of the document we're in, so
  612.      * I grab the parent of the Pages window (the document) and
  613.      * send it DOCM_PDOCUMENT which returns us the pointer.
  614.      * Roundabout, but it works.
  615.      */
  616.  
  617.     pDoc=(PCDocument)SendMessage(GetParent(m_hWnd), DOCM_PDOCUMENT
  618.         , 0, 0L);
  619.  
  620.     if (NULL!=pDoc)
  621.         pDoc->FilenameGet(szFile, CCHPATHMAX);
  622.     else
  623.         szFile[0]=0;
  624.  
  625.     //CHAPTER21MOD
  626.     NotifyOfRename(szFile, NULL, NULL);
  627.     //End CHAPTER21MOD
  628.  
  629.     /*
  630.      * If we're creating an iconic aspect object and we have
  631.      * an object from the Insert Object dialog, then we need to
  632.      * store that iconic presentation in the cache, handled
  633.      * with the utility function INOLE_SwitchDisplayAspect.  In
  634.      * this case dwData is a handle to the metafile containing
  635.      * the icon.  If dwData is NULL then we depend on the
  636.      * server to provide the aspect, in which case we need
  637.      * a view advise.
  638.      */
  639.  
  640.     if (DVASPECT_ICON & m_fe.dwAspect)
  641.         {
  642.         DWORD           dw=DVASPECT_CONTENT;
  643.         IAdviseSink    *pSink;
  644.  
  645.         pSink=(NULL==dwData) ? NULL : m_pImpIAdviseSink;
  646.  
  647.         INOLE_SwitchDisplayAspect(m_pIOleObject, &dw
  648.             , DVASPECT_ICON, (HGLOBAL)(UINT)dwData, FALSE
  649.             , (NULL!=dwData), pSink, NULL);
  650.         }
  651.  
  652.     return TRUE;
  653.     }
  654.  
  655.  
  656.  
  657.  
  658. /*
  659.  * CTenant::Open
  660.  *
  661.  * Purpose:
  662.  *  Retrieves the IStorage associated with this tenant.  The
  663.  *  IStorage is owned by the tenant and thus the tenant always
  664.  *  holds a reference count.
  665.  *
  666.  *  If the storage is already open for this tenant, then this
  667.  *  function will AddRef it; therefore the caller must always
  668.  *  match an Open with a Close.
  669.  *
  670.  * Parameters:
  671.  *  pIStorage       LPSTORAGE above this tenant (which has its
  672.  *                  own storage).
  673.  *
  674.  * Return Value:
  675.  *  BOOL            TRUE if opening succeeds, FALSE otherwise.
  676.  */
  677.  
  678. BOOL CTenant::Open(LPSTORAGE pIStorage)
  679.     {
  680.     HRESULT     hr=NOERROR;
  681.     DWORD       dwMode=STGM_TRANSACTED | STGM_READWRITE
  682.                     | STGM_SHARE_EXCLUSIVE;
  683.     OLECHAR     szTemp[32];
  684.  
  685.     if (NULL==m_pIStorage)
  686.         {
  687.         if (NULL==pIStorage)
  688.             return FALSE;
  689.  
  690.         /*
  691.          * Attempt to open the storage under this ID.  If there is
  692.          * none, then create it.  In either case we end up with an
  693.          * IStorage that we either save in pPage or release.
  694.          */
  695.  
  696.         GetStorageName(szTemp);
  697.         hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0
  698.             , &m_pIStorage);
  699.  
  700.         if (FAILED(hr))
  701.             {
  702.             hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0
  703.                 , &m_pIStorage);
  704.             }
  705.         }
  706.     else
  707.         m_pIStorage->AddRef();
  708.  
  709.     if (FAILED(hr))
  710.         return FALSE;
  711.  
  712.     m_cOpens++;
  713.  
  714.     //Create these if we don't have them already.
  715.     if (NULL==m_pImpIOleClientSite && NULL==m_pImpIAdviseSink)
  716.         {
  717.         m_pImpIOleClientSite=new CImpIOleClientSite(this, this);
  718.         m_pImpIAdviseSink=new CImpIAdviseSink(this, this);
  719.  
  720.         if (NULL==m_pImpIOleClientSite || NULL==m_pImpIAdviseSink)
  721.             return FALSE;
  722.         }
  723.  
  724.     return TRUE;
  725.     }
  726.  
  727.  
  728.  
  729.  
  730. /*
  731.  * CTenant::Close
  732.  *
  733.  * Purpose:
  734.  *  Possibly commits the storage, then releases it reversing the
  735.  *  reference count from Open.  If the reference on the storage
  736.  *  goes to zero, the storage is forgotten.  However, the object we
  737.  *  contain is still held and as long as it's active the storage
  738.  *  remains alive.
  739.  *
  740.  * Parameters:
  741.  *  fCommit         BOOL indicating if we're to commit.
  742.  *
  743.  * Return Value:
  744.  *  None
  745.  */
  746.  
  747. void CTenant::Close(BOOL fCommit)
  748.     {
  749.     if (fCommit)
  750.         Update();
  751.  
  752.     if (NULL!=m_pIStorage)
  753.         {
  754.         m_pIStorage->Release();
  755.  
  756.         /*
  757.          * We can't use a zero reference count to know when to NULL
  758.          * this since other things might have AddRef'd the storage.
  759.          */
  760.         if (0==--m_cOpens)
  761.             {
  762.             m_pIStorage=NULL;
  763.  
  764.             //Close the object saving if necessary
  765.             if (NULL!=m_pIOleObject)
  766.                 {
  767.                 m_pIOleObject->Close(OLECLOSE_SAVEIFDIRTY);
  768.                 ReleaseInterface(m_pIOleObject);
  769.                 }
  770.  
  771.             //Release all other held pointers
  772.             if (NULL!=m_pIViewObject2)
  773.                 {
  774.                 m_pIViewObject2->SetAdvise(m_fe.dwAspect, 0, NULL);
  775.                 ReleaseInterface(m_pIViewObject2);
  776.                 }
  777.  
  778.             //We know we only hold one ref from Create or Load
  779.             ReleaseInterface(m_pObj);
  780.             }
  781.         }
  782.  
  783.     return;
  784.     }
  785.  
  786.  
  787.  
  788.  
  789. /*
  790.  * CTenant::Update
  791.  *
  792.  * Purpose:
  793.  *  Forces a common on the page if it's open.
  794.  *
  795.  * Parameters:
  796.  *  None
  797.  *
  798.  * Return Value:
  799.  *  BOOL            TRUE if the object is open, FALSE otherwise.
  800.  */
  801.  
  802. BOOL CTenant::Update(void)
  803.     {
  804.     LPPERSISTSTORAGE    pIPS;
  805.  
  806.     if (NULL!=m_pIStorage)
  807.         {
  808.         /*
  809.          * We need to OleSave again because we might have changed
  810.          * the size or position of this tenant.  We also need to
  811.          * save the rectangle on the page, since that's not known
  812.          * to OLE.
  813.          */
  814.         m_pObj->QueryInterface(IID_IPersistStorage, (PPVOID)&pIPS);
  815.  
  816.         //This fails for static objects...so we improvise if so
  817.         if (FAILED(OleSave(pIPS, m_pIStorage, TRUE)))
  818.             {
  819.             //This is essentially what OleSave does.
  820.             WriteClassStg(m_pIStorage, m_clsID);
  821.             pIPS->Save(m_pIStorage, TRUE);
  822.             }
  823.  
  824.         pIPS->SaveCompleted(NULL);
  825.         pIPS->Release();
  826.  
  827.         m_pIStorage->Commit(STGC_DEFAULT);
  828.         }
  829.  
  830.     return FALSE;
  831.     }
  832.  
  833.  
  834.  
  835.  
  836.  
  837. /*
  838.  * CTenant::Destroy
  839.  *
  840.  * Purpose:
  841.  *  Removes this page from the given storage.  The caller should
  842.  *  eventually delete this CTenant object to free the object herein.
  843.  *  Nothing is committed when being destroyed.
  844.  *
  845.  * Parameters:
  846.  *  pIStorage       LPSTORAGE contianing this page on which to call
  847.  *                  DestroyElement
  848.  *
  849.  * Return Value:
  850.  *  None
  851.  */
  852.  
  853. void CTenant::Destroy(LPSTORAGE pIStorage)
  854.     {
  855.     OLECHAR     szTemp[32];
  856.  
  857.     if (NULL!=pIStorage)
  858.         {
  859.         if (NULL!=m_pIOleObject)
  860.             m_pIOleObject->Close(OLECLOSE_NOSAVE);
  861.  
  862.         if (NULL!=m_pIStorage)
  863.             {
  864.             //Remove all reference/open counts on this storage.
  865.             while (0!=m_cOpens)
  866.                 {
  867.                 m_pIStorage->Release();
  868.                 m_cOpens--;
  869.                 }
  870.             }
  871.  
  872.         GetStorageName(szTemp);
  873.         pIStorage->DestroyElement(szTemp);
  874.  
  875.         m_pIStorage=NULL;
  876.         }
  877.  
  878.     return;
  879.     }
  880.  
  881.  
  882.  
  883.  
  884. /*
  885.  * CTenant::Select
  886.  *
  887.  * Purpose:
  888.  *  Selects or deselects the tenant.
  889.  *
  890.  * Parameters:
  891.  *  fSelect         BOOL indicating the new state of the tenant.
  892.  *
  893.  * Return Value:
  894.  *  None
  895.  */
  896.  
  897. void CTenant::Select(BOOL fSelect)
  898.     {
  899.     BOOL        fWasSelected;
  900.     DWORD       dwState;
  901.     RECT        rc;
  902.     HDC         hDC;
  903.  
  904.     fWasSelected=(BOOL)(TENANTSTATE_SELECTED & m_dwState);
  905.  
  906.     //Nothing to do when there's no change.
  907.     if (fWasSelected==fSelect)
  908.         return;
  909.  
  910.     dwState=m_dwState & ~TENANTSTATE_SELECTED;
  911.     m_dwState=dwState | ((fSelect) ? TENANTSTATE_SELECTED : 0);
  912.  
  913.     /*
  914.      * Draw sizing handles to show the selection state.  We convert
  915.      * things to MM_TEXT since that's what this function expects.
  916.      */
  917.  
  918.     RECTFROMRECTL(rc, m_rcl);
  919.     RectConvertMappings(&rc, NULL, TRUE);
  920.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  921.  
  922.     hDC=GetDC(m_hWnd);
  923.  
  924.     UIDrawHandles(&rc, hDC, UI_HANDLES_INSIDE
  925.         | UI_HANDLES_NOBORDER | UI_HANDLES_USEINVERSE
  926.         , CXYHANDLE, !fWasSelected);
  927.  
  928.     ReleaseDC(m_hWnd, hDC);
  929.  
  930.     if (fSelect)
  931.         m_pPG->m_fDirty=TRUE;
  932.  
  933.     return;
  934.     }
  935.  
  936.  
  937.  
  938.  
  939. /*
  940.  * CTenant::ShowAsOpen
  941.  *
  942.  * Purpose:
  943.  *  Draws or removes the hatch pattern over an object.
  944.  *
  945.  * Parameters:
  946.  *  fOpen           BOOL indicating the open state of this tenant.
  947.  *
  948.  * Return Value:
  949.  *  None
  950.  */
  951.  
  952. void CTenant::ShowAsOpen(BOOL fOpen)
  953.     {
  954.     BOOL        fWasOpen;
  955.     DWORD       dwState;
  956.     RECT        rc;
  957.     HDC         hDC;
  958.  
  959.     fWasOpen=(BOOL)(TENANTSTATE_OPEN & m_dwState);
  960.  
  961.     dwState=m_dwState & ~TENANTSTATE_OPEN;
  962.     m_dwState=dwState | ((fOpen) ? TENANTSTATE_OPEN : 0);
  963.  
  964.     //If this was not open, then just hatch, otherwise repaint.
  965.     if (!fWasOpen && fOpen)
  966.         {
  967.         RECTFROMRECTL(rc, m_rcl);
  968.         RectConvertMappings(&rc, NULL, TRUE);
  969.         OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  970.  
  971.         hDC=GetDC(m_hWnd);
  972.         UIDrawShading(&rc, hDC, UI_SHADE_FULLRECT, 0);
  973.         ReleaseDC(m_hWnd, hDC);
  974.         }
  975.  
  976.     if (fWasOpen && !fOpen)
  977.         Repaint();
  978.  
  979.     return;
  980.     }
  981.  
  982.  
  983.  
  984.  
  985.  
  986. /*
  987.  * CTenant::ShowYourself
  988.  *
  989.  * Purpose:
  990.  *  Function that really just implements IOleClientSite::ShowObject.
  991.  *  Here we first check if the tenant is fully visible, and if so,
  992.  *  then nothing needs to happen.  Otherwise, if the upper left
  993.  *  corner of the tenant is in the upper left visible quadrant of
  994.  *  the window, we'll also consider ourselves done.  Otherwise
  995.  *  we'll put the upper left corner of the object at the upper left
  996.  *  corner of the window.
  997.  *
  998.  * Parameters:
  999.  *  None
  1000.  *
  1001.  * Return Value:
  1002.  *  None
  1003.  */
  1004.  
  1005. void CTenant::ShowYourself(void)
  1006.     {
  1007.     RECTL       rcl;
  1008.     RECT        rc;
  1009.     POINT       pt1, pt2;
  1010.  
  1011.     //Scrolling deals in device units; get our rectangle in those.
  1012.     RectGet(&rcl, TRUE);
  1013.  
  1014.     //Get the window rectangle offset for the current scroll pos.
  1015.     GetClientRect(m_hWnd, &rc);
  1016.     OffsetRect(&rc, m_pPG->m_xPos, m_pPG->m_yPos);
  1017.  
  1018.     //Check if the object is already visible. (macro in bookguid.h)
  1019.     SETPOINT(pt1, (int)rcl.left,  (int)rcl.top);
  1020.     SETPOINT(pt2, (int)rcl.right, (int)rcl.bottom);
  1021.  
  1022.     if (PtInRect(&rc, pt1) && PtInRect(&rc, pt2))
  1023.         return;
  1024.  
  1025.     //Check if the upper left is within the upper left quadrant
  1026.     if (((int)rcl.left > rc.left
  1027.         && (int)rcl.left < ((rc.right+rc.left)/2))
  1028.         && ((int)rcl.top > rc.top
  1029.         && (int)rcl.top < ((rc.bottom+rc.top)/2)))
  1030.         return;
  1031.  
  1032.     //These are macros in INC\BOOK1632.H
  1033.     SendScrollPosition(m_hWnd, WM_HSCROLL, rcl.left-8);
  1034.     SendScrollPosition(m_hWnd, WM_VSCROLL, rcl.top-8);
  1035.     return;
  1036.     }
  1037.  
  1038.  
  1039.  
  1040. /*
  1041.  * CTenant::AddVerbMenu
  1042.  *
  1043.  * Purpose:
  1044.  *  Creates the variable verb menu item for the object in this
  1045.  *  tenant.
  1046.  *
  1047.  * Parmeters:
  1048.  *  hMenu           HMENU on which to add items.
  1049.  *  iPos            UINT position on that menu to add items.
  1050.  *
  1051.  * Return Value:
  1052.  *  None
  1053.  */
  1054.  
  1055. void CTenant::AddVerbMenu(HMENU hMenu, UINT iPos)
  1056.     {
  1057.     HMENU       hMenuTemp;
  1058.     LPOLEOBJECT pObj=m_pIOleObject;
  1059.  
  1060.     //If we're static, say we have no object.
  1061.     if (TENANTTYPE_STATIC==m_tType)
  1062.         pObj=NULL;
  1063.  
  1064.     OleUIAddVerbMenu(pObj, NULL, hMenu, iPos, IDM_VERBMIN
  1065.         , IDM_VERBMAX, TRUE, IDM_EDITCONVERT, &hMenuTemp);
  1066.  
  1067.     return;
  1068.     }
  1069.  
  1070.  
  1071.  
  1072.  
  1073. /*
  1074.  * CTenant::TypeGet
  1075.  *
  1076.  * Purpose:
  1077.  *  Returns the type of this tenant
  1078.  *
  1079.  * Parameters:
  1080.  *  None
  1081.  *
  1082.  * Return Value:
  1083.  *  TENANTTYPE      Type of the tenant.
  1084.  */
  1085.  
  1086. TENANTTYPE CTenant::TypeGet(void)
  1087.     {
  1088.     return m_tType;
  1089.     }
  1090.  
  1091.  
  1092.  
  1093.  
  1094.  
  1095.  
  1096. /*
  1097.  * CTenant::CopyEmbeddedObject
  1098.  *
  1099.  * Purpose:
  1100.  *  Copies an embedded object to the given data object (via SetData,
  1101.  *  assuming this is a data transfer object for clipboard/drag-drop)
  1102.  *  if that's what we're holding.
  1103.  *
  1104.  * Parameters:
  1105.  *  pIDataObject    LPDATAOBJECT in which to store the copy.
  1106.  *  pFE             LPFORMATETC into which to copy CFSTR_EMBEDDEDOBJECT
  1107.  *                  if we put that in the data object.
  1108.  *  pptl            PPOINTL to the pick point (NULL outside of
  1109.  *                  drag-drop);
  1110.  *
  1111.  * Return Value:
  1112.  *  None
  1113.  */
  1114.  
  1115. void CTenant::CopyEmbeddedObject(LPDATAOBJECT pIDataObject
  1116.     , LPFORMATETC pFE, PPOINTL pptl)
  1117.     {
  1118.     LPPERSISTSTORAGE    pIPS;
  1119.     STGMEDIUM           stm;
  1120.     FORMATETC           fe;
  1121.     HRESULT             hr;
  1122.     UINT                cf;
  1123.     POINTL              ptl;
  1124.     SIZEL               szl;
  1125.  
  1126.     //Can only copy embeddings.
  1127.     if (TENANTTYPE_EMBEDDEDOBJECT!=m_tType || NULL==m_pIOleObject)
  1128.         return;
  1129.  
  1130.     if (NULL==pptl)
  1131.         {
  1132.         SETPOINTL(ptl, 0, 0);
  1133.         pptl=&ptl;
  1134.         }
  1135.  
  1136.     /*
  1137.      * Create CFSTR_EMBEDDEDOBJECT.  This is simply an IStorage with
  1138.      * a copy of the embedded object in it.  The not-so-simple part
  1139.      * is getting an IStorage to stuff it in.  For this operation
  1140.      * we'll use a temporary compound file.
  1141.      */
  1142.  
  1143.     stm.pUnkForRelease=NULL;
  1144.     stm.tymed=TYMED_ISTORAGE;
  1145.     hr=StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE
  1146.         | STGM_CREATE| STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE
  1147.         , 0, &stm.pstg);
  1148.  
  1149.     if (FAILED(hr))
  1150.         return;
  1151.  
  1152.     m_pObj->QueryInterface(IID_IPersistStorage, (PPVOID)&pIPS);
  1153.  
  1154.     if (NOERROR==pIPS->IsDirty())
  1155.         {
  1156.         OleSave(pIPS, stm.pstg, FALSE);
  1157.         pIPS->SaveCompleted(NULL);
  1158.         }
  1159.     else
  1160.         m_pIStorage->CopyTo(0, NULL, NULL, stm.pstg);
  1161.  
  1162.     pIPS->Release();
  1163.  
  1164.     //stm.pstg now has a copy, so stuff it away.
  1165.     cf=RegisterClipboardFormat(CFSTR_EMBEDDEDOBJECT);
  1166.     SETDefFormatEtc(fe, cf, TYMED_ISTORAGE);
  1167.  
  1168.     if (SUCCEEDED(pIDataObject->SetData(&fe, &stm, TRUE)))
  1169.         *pFE=fe;
  1170.     else
  1171.         ReleaseStgMedium(&stm);
  1172.  
  1173.     stm.tymed=TYMED_HGLOBAL;
  1174.  
  1175.     /*
  1176.      * You want to make sure that if this object is iconic, that you
  1177.      * create the object descriptor with DVASPECT_ICON instead of
  1178.      * the more typical DVASPECT_CONTENT.  Also remember that
  1179.      * the pick point is in HIMETRIC.
  1180.      */
  1181.     XformSizeInPixelsToHimetric(NULL, (LPSIZEL)pptl, (LPSIZEL)&ptl);
  1182.  
  1183.     SETSIZEL(szl, (10*(m_rcl.right-m_rcl.left))
  1184.         , (10 * (m_rcl.bottom-m_rcl.top)));
  1185.  
  1186.     stm.hGlobal=INOLE_ObjectDescriptorFromOleObject
  1187.         (m_pIOleObject, m_fe.dwAspect, ptl, &szl);
  1188.  
  1189.     cf=RegisterClipboardFormat(CFSTR_OBJECTDESCRIPTOR);
  1190.     SETDefFormatEtc(fe, cf, TYMED_HGLOBAL);
  1191.  
  1192.     if (FAILED(pIDataObject->SetData(&fe, &stm, TRUE)))
  1193.         ReleaseStgMedium(&stm);
  1194.  
  1195.     return;
  1196.     }
  1197.  
  1198.  
  1199.  
  1200.  
  1201. //CHAPTER21MOD
  1202. /*
  1203.  * CTenant::CopyLinkedObject
  1204.  *
  1205.  * Purpose:
  1206.  *  Copies an linked object to the given data object (via SetData,
  1207.  *  assuming this is a data transfer object for clipboard/drag-drop)
  1208.  *  if that's what we're holding.
  1209.  *
  1210.  * Parameters:
  1211.  *  pIDataObject    LPDATAOBJECT in which to store the copy.
  1212.  *  pFE             LPFORMATETC into which to copy CF_LINKSOURCE
  1213.  *                  if we put that in the data object.
  1214.  *  pptl            PPOINTL to the pick point (NULL outside of
  1215.  *                  drag-drop);
  1216.  *
  1217.  * Return Value:
  1218.  *  None
  1219.  */
  1220.  
  1221. void CTenant::CopyLinkedObject(LPDATAOBJECT pIDataObject
  1222.     , LPFORMATETC pFE, PPOINTL pptl)
  1223.     {
  1224.     STGMEDIUM           stm;
  1225.     FORMATETC           fe;
  1226.     HRESULT             hr;
  1227.     UINT                cf;
  1228.     POINTL              ptl;
  1229.     LPMONIKER           pmk;
  1230.     CLSID               clsID;
  1231.     LPTSTR              psz=NULL;
  1232.     SIZEL               szl;
  1233.  
  1234.     //Can only copy links to embeddings from here.
  1235.     if (TENANTTYPE_EMBEDDEDOBJECT!=m_tType || NULL==m_pIOleObject)
  1236.         return;
  1237.  
  1238.     //If we don't have a full moniker, no linking allowed
  1239.     if (NULL==m_pmk)
  1240.         return;
  1241.  
  1242.     //If the object doesn't support this, return.
  1243.     if (OLEMISC_CANTLINKINSIDE & m_grfMisc)
  1244.         return;
  1245.  
  1246.     if (NULL==pptl)
  1247.         {
  1248.         SETPOINTL(ptl, 0, 0);
  1249.         pptl=&ptl;
  1250.         }
  1251.  
  1252.     /*
  1253.      * We need to get CFSTR_LINKSOURCE, but the server may not be
  1254.      * running, in which case we just grab the moniker and CLSID
  1255.      * for this object and call INOLE_GetLinkSourceData.
  1256.      */
  1257.  
  1258.     m_pIOleObject->GetUserClassID(&clsID);
  1259.     hr=m_pIOleObject->GetMoniker(0, OLEWHICHMK_OBJFULL, &pmk);
  1260.  
  1261.     if (FAILED(hr))
  1262.         return;
  1263.  
  1264.     stm.pUnkForRelease=NULL;
  1265.     stm.tymed=TYMED_NULL;
  1266.     cf=RegisterClipboardFormat(CFSTR_LINKSOURCE);
  1267.     SETDefFormatEtc(fe, cf, TYMED_ISTREAM);
  1268.     hr=INOLE_GetLinkSourceData(pmk, &clsID, &fe, &stm);
  1269.  
  1270.     if (FAILED(hr))
  1271.         {
  1272.         pmk->Release();
  1273.         return;
  1274.         }
  1275.  
  1276.     //Send it to the data object for transfer
  1277.     if (SUCCEEDED(pIDataObject->SetData(&fe, &stm, TRUE)))
  1278.         *pFE=fe;
  1279.     else
  1280.         ReleaseStgMedium(&stm);
  1281.  
  1282.     XformSizeInPixelsToHimetric(NULL, (LPSIZEL)pptl, (LPSIZEL)&ptl);
  1283.  
  1284.     SETSIZEL(szl, (10*(m_rcl.right-m_rcl.left))
  1285.         , (10 * (m_rcl.bottom-m_rcl.top)));
  1286.  
  1287.     stm.hGlobal=INOLE_ObjectDescriptorFromOleObject
  1288.         (m_pIOleObject, m_fe.dwAspect, ptl, &szl);
  1289.  
  1290.     //Better set these properly or errors occur.
  1291.     stm.tymed=TYMED_HGLOBAL;
  1292.     stm.pUnkForRelease=NULL;
  1293.  
  1294.     cf=RegisterClipboardFormat(CFSTR_LINKSRCDESCRIPTOR);
  1295.     SETDefFormatEtc(fe, cf, TYMED_HGLOBAL);
  1296.  
  1297.     if (FAILED(pIDataObject->SetData(&fe, &stm, TRUE)))
  1298.         ReleaseStgMedium(&stm);
  1299.  
  1300.     return;
  1301.     }
  1302. //End CHAPTER21MOD
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308. /*
  1309.  * CTenant::ShowObjectType
  1310.  *
  1311.  * Purpose:
  1312.  *  Tells the object to switch on or off an indication of whether
  1313.  *  it is linked or embedded.
  1314.  *
  1315.  * Parameters:
  1316.  *  fShow           BOOL indicating to show the type (TRUE) or
  1317.  *                  not (FALSE)
  1318.  *
  1319.  * Return Value:
  1320.  *  None
  1321.  */
  1322.  
  1323. void CTenant::ShowObjectType(BOOL fShow)
  1324.     {
  1325.     BOOL        fWasShow;
  1326.     DWORD       dwState;
  1327.     RECT        rc;
  1328.     HDC         hDC;
  1329.  
  1330.     fWasShow=(BOOL)(TENANTSTATE_SHOWTYPE & m_dwState);
  1331.  
  1332.     dwState=m_dwState & ~TENANTSTATE_SHOWTYPE;
  1333.     m_dwState=dwState | ((fShow) ? TENANTSTATE_SHOWTYPE : 0);
  1334.  
  1335.     /*
  1336.      * If this wasn't previously shown, just add the line,
  1337.      * otherwise repaint.
  1338.      */
  1339.     if (!fWasShow && fShow)
  1340.         {
  1341.         RECTFROMRECTL(rc, m_rcl);
  1342.         RectConvertMappings(&rc, NULL, TRUE);
  1343.         OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  1344.  
  1345.         hDC=GetDC(m_hWnd);
  1346.         UIShowObject(&rc, hDC, (TENANTTYPE_LINKEDOBJECT==m_tType));
  1347.         ReleaseDC(m_hWnd, hDC);
  1348.         }
  1349.  
  1350.     if (fWasShow && !fShow)
  1351.         Repaint();
  1352.  
  1353.     return;
  1354.     }
  1355.  
  1356.  
  1357.  
  1358.  
  1359.  
  1360. /*
  1361.  * CTenant::NotifyOfRename
  1362.  *
  1363.  * Purpose:
  1364.  *  Instructs the tenant that the document was saved under a
  1365.  *  different name.  In order to keep the right compound document
  1366.  *  user interface, this tenant needs to tell its object through
  1367.  *  IOleObject::SetHostNames.
  1368.  *
  1369.  * Parameters:
  1370.  *  pszFile         LPTSTR of filename.
  1371.  *  pmkFile         LPMONIKER of the new filename.  If this and
  1372.  *                  pmkPage are NULL then nothing happens with
  1373.  *                  monikers.
  1374.  *  pmkPage         LPMONIKER of the page we're in.
  1375.  *
  1376.  * Return Value:
  1377.  *  None
  1378.  */
  1379.  
  1380. //CHAPTER21MOD
  1381. void CTenant::NotifyOfRename(LPTSTR pszFile, LPMONIKER pmkFile
  1382.     , LPMONIKER pmkPage)
  1383. //End CHAPTER21MOD
  1384.     {
  1385.     TCHAR       szObj[40];
  1386.     TCHAR       szApp[40];
  1387.  
  1388.     if (NULL==m_pIOleObject)
  1389.         return;
  1390.  
  1391.     if (TEXT('\0')==*pszFile)
  1392.         {
  1393.         LoadString(m_pPG->m_hInst, IDS_UNTITLED, szObj
  1394.             , sizeof(szObj));
  1395.         }
  1396.     else
  1397.         {
  1398.         GetFileTitle(pszFile, szObj, sizeof(szObj));
  1399.  
  1400.        #ifndef WIN32
  1401.         //Force filenames to uppercase in DOS versions.
  1402.         AnsiUpper(szObj);
  1403.        #endif
  1404.         }
  1405.  
  1406.     LoadString(m_pPG->m_hInst, IDS_CAPTION, szApp, sizeof(szApp));
  1407.    #ifdef WIN32ANSI
  1408.     OLECHAR     szObjW[40], szAppW[40];
  1409.  
  1410.     MultiByteToWideChar(CP_ACP, 0, szObj, -1, szObjW, 40);
  1411.     MultiByteToWideChar(CP_ACP, 0, szApp, -1, szAppW, 40);
  1412.     m_pIOleObject->SetHostNames(szAppW, szObjW);
  1413.    #else
  1414.     m_pIOleObject->SetHostNames(szApp, szObj);
  1415.    #endif
  1416.  
  1417.     //CHAPTER21MOD
  1418.     if (NULL!=pmkFile)
  1419.         {
  1420.         ReleaseInterface(m_pmkFile);
  1421.         m_pmkFile=pmkFile;
  1422.         m_pmkFile->AddRef();
  1423.  
  1424.         m_pIOleObject->SetMoniker(OLEWHICHMK_CONTAINER, pmkFile);
  1425.         }
  1426.  
  1427.     if (NULL!=pmkFile && NULL!=pmkPage)
  1428.         {
  1429.         LPMONIKER   pmkTenant=NULL;
  1430.         LPMONIKER   pmkRel=NULL;
  1431.         HRESULT     hr;
  1432.  
  1433.         //Create the moniker for this tenant.
  1434.        #ifdef WIN32ANSI
  1435.         GetStorageName(szObjW);
  1436.         WideCharToMultiByte(CP_ACP, 0, szObjW, -1, szObj, 40
  1437.            , NULL, NULL);
  1438.        #else
  1439.         GetStorageName(szObj);
  1440.        #endif
  1441.         hr=CreateItemMoniker(TEXT("!"), szObj, &pmkTenant);
  1442.  
  1443.         if (SUCCEEDED(hr))
  1444.             {
  1445.             //Create the relative moniker, i.e. no pathname.
  1446.             hr=pmkPage->ComposeWith(pmkTenant, FALSE, &pmkRel);
  1447.             pmkTenant->Release();
  1448.  
  1449.             //Hold on to the relative moniker
  1450.             ReleaseInterface(m_pmk);
  1451.             m_pmk=pmkRel;
  1452.  
  1453.             if (SUCCEEDED(hr))
  1454.                 m_pIOleObject->SetMoniker(OLEWHICHMK_OBJREL, pmkRel);
  1455.             }
  1456.         }
  1457.  
  1458.     /*
  1459.      * Note that this tenant is already registered as running
  1460.      * because the page registered a wildcard.
  1461.      */
  1462.     //End CHAPTER21MOD
  1463.  
  1464.     return;
  1465.     }
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471. /*
  1472.  * CTenant::Activate
  1473.  *
  1474.  * Purpose:
  1475.  *  Activates a verb on the object living in the tenant.  Does
  1476.  *  nothing for static objects.
  1477.  *
  1478.  * Parameters:
  1479.  *  iVerb           LONG of the verb to execute.
  1480.  *
  1481.  * Return Value:
  1482.  *  BOOL            TRUE if the object changed due to this verb
  1483.  *                  execution.
  1484.  */
  1485.  
  1486. BOOL CTenant::Activate(LONG iVerb)
  1487.     {
  1488.     RECT        rc, rcH;
  1489.     CHourglass *pHour;
  1490.     SIZEL       szl;
  1491.  
  1492.     //Can't activate statics.
  1493.     if (TENANTTYPE_STATIC==m_tType || NULL==m_pIOleObject)
  1494.         {
  1495.         MessageBeep(0);
  1496.         return FALSE;
  1497.         }
  1498.  
  1499.     RECTFROMRECTL(rc, m_rcl);
  1500.     RectConvertMappings(&rc, NULL, TRUE);
  1501.     XformRectInPixelsToHimetric(NULL, &rc, &rcH);
  1502.  
  1503.     pHour=new CHourglass;
  1504.  
  1505.     //Get the server running first, then do a SetExtent, then show it
  1506.     OleRun(m_pIOleObject);
  1507.  
  1508.     if (m_fSetExtent)
  1509.         {
  1510.         SETSIZEL(szl, rcH.right-rcH.left, rcH.top-rcH.bottom);
  1511.         m_pIOleObject->SetExtent(m_fe.dwAspect, &szl);
  1512.         m_fSetExtent=FALSE;
  1513.         }
  1514.  
  1515.     m_pIOleObject->DoVerb(iVerb, NULL, m_pImpIOleClientSite, 0
  1516.         , m_hWnd, &rcH);
  1517.  
  1518.     delete pHour;
  1519.  
  1520.     //If object changes, IAdviseSink::OnViewChange will see it.
  1521.     return FALSE;
  1522.     }
  1523.  
  1524.  
  1525.  
  1526.  
  1527.  
  1528.  
  1529. /*
  1530.  * CTenant::Draw
  1531.  *
  1532.  * Purpose:
  1533.  *  Draws the tenant in its rectangle on the given hDC.  We assume
  1534.  *  the DC is already set up for the mapping mode in which our
  1535.  *  rectangle is expressed, since the Page we're in tells us both
  1536.  *  the rect and the hDC.
  1537.  *
  1538.  * Parameters:
  1539.  *  hDC             HDC in which to draw.  Could be a metafile,
  1540.  *                  memory DC, screen, or printer.
  1541.  *  ptd             DVTARGETDEVICE * describing the device.
  1542.  *  hIC             HDC holding an information context (printing).
  1543.  *  xOff, yOff      int offsets for the page in lometric
  1544.  *  fNoColor        BOOL indicating if we should do B & W
  1545.  *  fPrinter        BOOL indicating if we should render for a
  1546.  *                  printer.
  1547.  *
  1548.  * Return Value:
  1549.  *  None
  1550.  */
  1551.  
  1552. void CTenant::Draw(HDC hDC, DVTARGETDEVICE *ptd, HDC hIC
  1553.     , int xOff, int yOff, BOOL fNoColor, BOOL fPrinter)
  1554.     {
  1555.     HRESULT         hr;
  1556.     RECT            rc;
  1557.     RECTL           rcl;
  1558.     UINT            uMM;
  1559.  
  1560.     RECTFROMRECTL(rc, m_rcl);
  1561.     OffsetRect(&rc, -xOff, -yOff);
  1562.     RECTLFROMRECT(rcl, rc);
  1563.  
  1564.     //Repaint erases the rectangle to insure full object cleanup
  1565.     if (!fNoColor && !fPrinter)
  1566.         {
  1567.         COLORREF    cr;
  1568.         cr=SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  1569.         ExtTextOut(hDC, rc.left, rc.top, ETO_OPAQUE, &rc, NULL
  1570.             , 0, NULL);
  1571.         SetBkColor(hDC, cr);
  1572.         }
  1573.  
  1574.     //We have to use Draw since we have a target device and IC.
  1575.     hr=m_pIViewObject2->Draw(m_fe.dwAspect, -1, NULL, ptd, hIC, hDC
  1576.         , &rcl, NULL, NULL, 0);
  1577.  
  1578.  
  1579.     /*
  1580.      * If Draw failed, then perhaps it couldn't work for the device,
  1581.      * so try good old OleDraw as a last resort.  The code will
  1582.      * generally be OLE_E_BLANK.
  1583.      */
  1584.     if (FAILED(hr))
  1585.         OleDraw(m_pObj, m_fe.dwAspect, hDC, &rc);
  1586.  
  1587.     if (!fPrinter)
  1588.         {
  1589.         /*
  1590.          * Draw sizing handles to show the selection state.  We
  1591.          * convert things to MM_TEXT since that's what this
  1592.          * function expects.
  1593.          */
  1594.         RectConvertMappings(&rc, NULL, TRUE);
  1595.         uMM=SetMapMode(hDC, MM_TEXT);
  1596.  
  1597.         if (TENANTSTATE_SELECTED & m_dwState)
  1598.             {
  1599.             UIDrawHandles(&rc, hDC, UI_HANDLES_INSIDE
  1600.                 | UI_HANDLES_NOBORDER | UI_HANDLES_USEINVERSE
  1601.                 , CXYHANDLE, TRUE);
  1602.             }
  1603.  
  1604.         if (TENANTSTATE_OPEN & m_dwState)
  1605.             UIDrawShading(&rc, hDC, UI_SHADE_FULLRECT, 0);
  1606.  
  1607.         //Distinguish linked and embedded objects.
  1608.         if (TENANTSTATE_SHOWTYPE & m_dwState)
  1609.             {
  1610.             UIShowObject(&rc, hDC
  1611.                 , (TENANTTYPE_LINKEDOBJECT==m_tType));
  1612.             }
  1613.  
  1614.         uMM=SetMapMode(hDC, uMM);
  1615.         }
  1616.  
  1617.     return;
  1618.     }
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624. /*
  1625.  * CTenant::Repaint
  1626.  * CTenant::Invalidate
  1627.  *
  1628.  * Purpose:
  1629.  *  Repaints the tenant where it lies or invalidates its area
  1630.  *  for later repainting.
  1631.  *
  1632.  * Parameters:
  1633.  *  None
  1634.  *
  1635.  * Return Value:
  1636.  *  None
  1637.  */
  1638.  
  1639. void CTenant::Repaint(void)
  1640.     {
  1641.     RECT        rc;
  1642.     HDC         hDC;
  1643.  
  1644.     /*
  1645.      * We might be asked to repaint from
  1646.      * IOleClientSite::OnShowWindow after we've switched pages if
  1647.      * our server was running. This check on m_cOpens prevents that.
  1648.      */
  1649.     if (0==m_cOpens || !m_fRepaintEnabled)
  1650.         return;
  1651.  
  1652.     hDC=GetDC(m_hWnd);
  1653.     SetRect(&rc, m_pPG->m_xPos, m_pPG->m_yPos, 0, 0);
  1654.     RectConvertMappings(&rc, NULL, FALSE);
  1655.  
  1656.     SetMapMode(hDC, MM_LOMETRIC);
  1657.     Draw(hDC, NULL, NULL, rc.left, rc.top, FALSE, FALSE);
  1658.  
  1659.     ReleaseDC(m_hWnd, hDC);
  1660.     return;
  1661.     }
  1662.  
  1663.  
  1664. void CTenant::Invalidate(void)
  1665.     {
  1666.     RECTL       rcl;
  1667.     RECT        rc;
  1668.  
  1669.     RectGet(&rcl, TRUE);
  1670.     RECTFROMRECTL(rc, rcl);
  1671.  
  1672.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  1673.     InvalidateRect(m_hWnd, &rc, FALSE);
  1674.  
  1675.     return;
  1676.     }
  1677.  
  1678.  
  1679.  
  1680.  
  1681.  
  1682. /*
  1683.  * CTenant::FIsSelected
  1684.  *
  1685.  * Purpose:
  1686.  *  Returns the selection state of this tenant.
  1687.  *
  1688.  * Parameters:
  1689.  *  None
  1690.  *
  1691.  * Return Value:
  1692.  *  BOOL            TRUE if selected, FALSE otherwise.
  1693.  */
  1694.  
  1695. BOOL CTenant::FIsSelected(void)
  1696.     {
  1697.     return (BOOL)(m_dwState & TENANTSTATE_SELECTED);
  1698.     }
  1699.  
  1700.  
  1701.  
  1702. /*
  1703.  * CTenant::ConvertToStatic
  1704.  *
  1705.  * Purpose:
  1706.  *  Changes the object that lives in this tenant to a static one.
  1707.  *
  1708.  * Parameters:
  1709.  *  None
  1710.  *
  1711.  * Return Value:
  1712.  *  BOOL            TRUE if successful, FALSE otherwise.
  1713.  */
  1714.  
  1715. BOOL CTenant::ConvertToStatic(void)
  1716.     {
  1717.     /*
  1718.      * If you SetSourceMoniker in IOleLink to NULL, then the link is
  1719.      * gone as far as OLE is concerned.  You only need to make sure
  1720.      * the user doesn't have access to other functionality for this
  1721.      * object, which we insure by changing our internal type.  We
  1722.      * set this on loading if GetSourceMoniker returns NULL.
  1723.      */
  1724.     m_tType=TENANTTYPE_STATIC;
  1725.     return TRUE;
  1726.     }
  1727.  
  1728.  
  1729.  
  1730.  
  1731.  
  1732.  
  1733. /*
  1734.  * CTenant::ObjectClassFormatAndIcon
  1735.  *
  1736.  * Purpose:
  1737.  *  Helper function for CPage::ConvertObject to retrieve necessary
  1738.  *  information about the object.
  1739.  *
  1740.  * Parameters:
  1741.  *  pClsID          LPCLSID in which to store the CLSID.
  1742.  *  pwFormat        LPWORD in which to store the clipboard format
  1743.  *                  used.
  1744.  *  ppszType        LPTSTR * in which to return a pointer to a
  1745.  *                  type string.
  1746.  *  phMetaIcon      HGLOBAL * in which to return the metafile
  1747.  *                  icon currently in use.
  1748.  *
  1749.  * Return Value:
  1750.  *  None
  1751.  */
  1752.  
  1753. void CTenant::ObjectClassFormatAndIcon(LPCLSID pClsID
  1754.     , LPWORD pwFormat, LPTSTR *ppszType, HGLOBAL *phMetaIcon
  1755.     , LPTSTR *ppszLabel)
  1756.     {
  1757.     HRESULT         hr;
  1758.     TCHAR           szType[128];
  1759.     LPDATAOBJECT    pIDataObject;
  1760.     FORMATETC       fe;
  1761.     STGMEDIUM       stm;
  1762.  
  1763.     if (TENANTTYPE_EMBEDDEDOBJECT!=m_tType || NULL==m_pIOleObject)
  1764.         return;
  1765.  
  1766.     if (NULL==pClsID || NULL==pwFormat || NULL==ppszType
  1767.         || NULL==phMetaIcon)
  1768.         return;
  1769.  
  1770.  
  1771.     /*
  1772.      * For embedded objects get the real CLSID of the object and
  1773.      * its format string.  If this fails then we can try to ask
  1774.      * the object, or we can look in the registry.
  1775.      */
  1776.  
  1777.     hr=ReadClassStg(m_pIStorage, pClsID);
  1778.  
  1779.     if (FAILED(hr))
  1780.         {
  1781.         hr=m_pIOleObject->GetUserClassID(pClsID);
  1782.  
  1783.         if (FAILED(hr))
  1784.             *pClsID=CLSID_NULL;
  1785.         }
  1786.  
  1787.  
  1788.     hr=ReadFmtUserTypeStg(m_pIStorage, pwFormat, ppszType);
  1789.  
  1790.     if (FAILED(hr))
  1791.         {
  1792.         *pwFormat=0;
  1793.         *ppszType=NULL;
  1794.  
  1795.         if (INOLE_GetUserTypeOfClass(*pClsID, 0, szType
  1796.             , sizeof(szType)))
  1797.             {
  1798.             *ppszType=INOLE_CopyString(szType);
  1799.             }
  1800.         }
  1801.  
  1802.     /*
  1803.      * Try to get the AuxUserType from the registry, using
  1804.      * the short version (registered under AuxUserType\2).
  1805.      * If that fails, just copy *ppszType.
  1806.      */
  1807.     *ppszLabel=NULL;
  1808.  
  1809.     if (INOLE_GetUserTypeOfClass(*pClsID, 2, szType
  1810.         , sizeof(szType)))
  1811.         {
  1812.         *ppszLabel=INOLE_CopyString(szType);
  1813.         }
  1814.     else
  1815.         *ppszLabel=INOLE_CopyString(*ppszType);
  1816.  
  1817.     //Get the icon for this thing, if we're iconic.
  1818.     *phMetaIcon=NULL;
  1819.  
  1820.     hr=m_pObj->QueryInterface(IID_IDataObject
  1821.         , (PPVOID)&pIDataObject);
  1822.  
  1823.     if (SUCCEEDED(hr))
  1824.         {
  1825.         SETFormatEtc(fe, CF_METAFILEPICT, DVASPECT_ICON, NULL
  1826.             , TYMED_MFPICT, -1);
  1827.         hr=pIDataObject->GetData(&fe, &stm);
  1828.         pIDataObject->Release();
  1829.  
  1830.         if (SUCCEEDED(hr))
  1831.             *phMetaIcon=stm.hGlobal;
  1832.         else
  1833.             *phMetaIcon=OleGetIconOfClass(*pClsID, NULL, TRUE);
  1834.         }
  1835.  
  1836.     return;
  1837.     }
  1838.  
  1839.  
  1840.  
  1841.  
  1842. /*
  1843.  * CTenant::SwitchOrUpdateAspect
  1844.  *
  1845.  * Purpose:
  1846.  *  Switches between DVASPECT_CONTENT and DVASPECT_ICON
  1847.  *
  1848.  * Parameters:
  1849.  *  hMetaIcon       HGLOBAL to the new icon if we're changing the
  1850.  *                  icon or switching to DVASPECT_ICON.  NULL to
  1851.  *                  change back to content.
  1852.  *  fPreserve       BOOL indicating if we're to preserve the old
  1853.  *                  aspect after changing.
  1854.  *
  1855.  * Return Value:
  1856.  *  BOOL            TRUE if anything changed, FALSE otherwise.
  1857.  */
  1858.  
  1859. BOOL CTenant::SwitchOrUpdateAspect(HGLOBAL hMetaIcon
  1860.     , BOOL fPreserve)
  1861.     {
  1862.     HRESULT     hr;
  1863.     DWORD       dwAspect;
  1864.     BOOL        fUpdate=FALSE;
  1865.  
  1866.     //Nothing to do if we're content already and there's no icon.
  1867.     if (NULL==hMetaIcon && DVASPECT_CONTENT==m_fe.dwAspect)
  1868.         return FALSE;
  1869.  
  1870.     //If we're iconic already, just cache the new icon
  1871.     if (NULL!=hMetaIcon && DVASPECT_ICON==m_fe.dwAspect)
  1872.         hr=INOLE_SetIconInCache(m_pIOleObject, hMetaIcon);
  1873.     else
  1874.         {
  1875.         //Otherwise, switch between iconic and content.
  1876.         dwAspect=(NULL==hMetaIcon) ? DVASPECT_CONTENT : DVASPECT_ICON;
  1877.  
  1878.         /*
  1879.          * Switch between aspects, where dwAspect has the new one
  1880.          * and m_fe.dwAspect will be changed in the process.
  1881.          */
  1882.         hr=INOLE_SwitchDisplayAspect(m_pIOleObject
  1883.             , &m_fe.dwAspect, dwAspect, hMetaIcon, !fPreserve
  1884.             , TRUE, m_pImpIAdviseSink, &fUpdate);
  1885.  
  1886.         if (SUCCEEDED(hr))
  1887.             {
  1888.             //Update MiscStatus for the new aspect
  1889.             m_pIOleObject->GetMiscStatus(m_fe.dwAspect, &m_grfMisc);
  1890.  
  1891.             if (fUpdate)
  1892.                 m_pIOleObject->Update();    //This repaints.
  1893.             }
  1894.         }
  1895.  
  1896.     //If we switched, update our extents.
  1897.     if (SUCCEEDED(hr))
  1898.         {
  1899.         SIZEL       szl;
  1900.  
  1901.         m_pIOleObject->GetExtent(m_fe.dwAspect, &szl);
  1902.  
  1903.         if (0 > szl.cy)
  1904.             szl.cy=-szl.cy;
  1905.  
  1906.         //Convert HIMETRIC absolute units to our LOMETRIC mapping
  1907.         if (0!=szl.cx && 0!=szl.cy)
  1908.             SETSIZEL(szl, szl.cx/10, -szl.cy/10);
  1909.  
  1910.         Invalidate();                   //Remove old aspect
  1911.         SizeSet(&szl, FALSE, FALSE);    //Change size
  1912.         Repaint();                      //Paint the new one
  1913.         }
  1914.  
  1915.     return SUCCEEDED(hr);
  1916.     }
  1917.  
  1918.  
  1919.  
  1920. /*
  1921.  * CTenant::EnableRepaint
  1922.  *
  1923.  * Purpose:
  1924.  *  Toggles whether the Repaint function does anything.  This
  1925.  *  is used during conversion/emulation of an object to disable
  1926.  *  repaints until the new object can be given the proper extents.
  1927.  *
  1928.  * Parameters:
  1929.  *  fEnable         TRUE to enable repaints, FALSE to disable.
  1930.  *
  1931.  * Return Value:
  1932.  *  None
  1933.  */
  1934.  
  1935. void CTenant::EnableRepaint(BOOL fEnable)
  1936.     {
  1937.     m_fRepaintEnabled=fEnable;
  1938.     return;
  1939.     }
  1940.  
  1941.  
  1942.  
  1943.  
  1944.  
  1945.  
  1946.  
  1947.  
  1948. /*
  1949.  * CTenant::ObjectGet
  1950.  *
  1951.  * Purpose:
  1952.  *  Retrieves the LPUNKNOWN of the object in use by this tenant
  1953.  *
  1954.  * Parameters:
  1955.  *  ppUnk           LPUNKNOWN * in which to return the object
  1956.  *                  pointer.
  1957.  *
  1958.  * Return Value:
  1959.  *  None
  1960.  */
  1961.  
  1962. void CTenant::ObjectGet(LPUNKNOWN *ppUnk)
  1963.     {
  1964.     if (NULL!=ppUnk)
  1965.         {
  1966.         *ppUnk=m_pObj;
  1967.         m_pObj->AddRef();
  1968.         }
  1969.  
  1970.     return;
  1971.     }
  1972.  
  1973.  
  1974.  
  1975.  
  1976.  
  1977. /*
  1978.  * CTenant::FormatEtcGet
  1979.  *
  1980.  * Purpose:
  1981.  *  Retrieves the FORMATETC in use by this tenant
  1982.  *
  1983.  * Parameters:
  1984.  *  pFE             LPFORMATETC in which to store the information.
  1985.  *  fPresentation   BOOL indicating if we want the real format or
  1986.  *                  that of the presentation.
  1987.  *
  1988.  * Return Value:
  1989.  *  None
  1990.  */
  1991.  
  1992. void CTenant::FormatEtcGet(LPFORMATETC pFE, BOOL fPresentation)
  1993.     {
  1994.     if (NULL!=pFE)
  1995.         {
  1996.         *pFE=m_fe;
  1997.  
  1998.         //If there is no format, use metafile (for embedded objects)
  1999.         if (fPresentation || 0==pFE->cfFormat)
  2000.             {
  2001.             //Don't mess with dwAspect; might be icon or content.
  2002.             pFE->cfFormat=CF_METAFILEPICT;
  2003.             pFE->tymed=TYMED_MFPICT;
  2004.             }
  2005.         }
  2006.  
  2007.     return;
  2008.     }
  2009.  
  2010.  
  2011.  
  2012.  
  2013.  
  2014. /*
  2015.  * CTenant::SizeGet
  2016.  * CTenant::SizeSet
  2017.  * CTenant::RectGet
  2018.  * CTenant::RectSet
  2019.  *
  2020.  * Purpose:
  2021.  *  Returns or sets the size/position of the object contained here.
  2022.  *
  2023.  * Parameters:
  2024.  *  pszl/prcl       LPSIZEL (Size) or LPRECTL (Rect) with the
  2025.  *                  extents of interest.  In Get situations,
  2026.  *                  this will receive the extents; in Set it
  2027.  *                  contains the extents.
  2028.  *  fDevice         BOOL indicating that pszl/prcl is expressed
  2029.  *                  in device units.  Otherwise it's LOMETRIC.
  2030.  *  fInformObj      (Set Only) BOOL indicating if we need to inform
  2031.  *                  the object all.
  2032.  *
  2033.  * Return Value:
  2034.  *  None
  2035.  */
  2036.  
  2037. void CTenant::SizeGet(LPSIZEL pszl, BOOL fDevice)
  2038.     {
  2039.     if (!fDevice)
  2040.         {
  2041.         pszl->cx=m_rcl.right-m_rcl.left;
  2042.         pszl->cy=m_rcl.bottom-m_rcl.top;
  2043.         }
  2044.     else
  2045.         {
  2046.         RECT        rc;
  2047.  
  2048.         SetRect(&rc, (int)(m_rcl.right-m_rcl.left)
  2049.             , (int)(m_rcl.bottom-m_rcl.top), 0, 0);
  2050.  
  2051.         RectConvertMappings(&rc, NULL, TRUE);
  2052.  
  2053.         pszl->cx=(long)rc.left;
  2054.         pszl->cy=(long)rc.top;
  2055.         }
  2056.  
  2057.     return;
  2058.     }
  2059.  
  2060.  
  2061. void CTenant::SizeSet(LPSIZEL pszl, BOOL fDevice, BOOL fInformObj)
  2062.     {
  2063.     SIZEL           szl;
  2064.  
  2065.     if (!fDevice)
  2066.         {
  2067.         szl=*pszl;
  2068.         m_rcl.right =pszl->cx+m_rcl.left;
  2069.         m_rcl.bottom=pszl->cy+m_rcl.top;
  2070.         }
  2071.     else
  2072.         {
  2073.         RECT        rc;
  2074.  
  2075.         SetRect(&rc, (int)pszl->cx, (int)pszl->cy, 0, 0);
  2076.         RectConvertMappings(&rc, NULL, FALSE);
  2077.  
  2078.         m_rcl.right =(long)rc.left+m_rcl.left;
  2079.         m_rcl.bottom=(long)rc.top+m_rcl.top;
  2080.  
  2081.         SETSIZEL(szl, (long)rc.left, (long)rc.top);
  2082.         }
  2083.  
  2084.  
  2085.     //Tell OLE that this object was resized.
  2086.     if (NULL!=m_pIOleObject && fInformObj)
  2087.         {
  2088.         HRESULT     hr;
  2089.         BOOL        fRun=FALSE;
  2090.  
  2091.         //Convert our LOMETRIC into HIMETRIC by *=10
  2092.         szl.cx*=10;
  2093.         szl.cy*=-10;    //Our size is stored negative.
  2094.  
  2095.         /*
  2096.          * If the MiscStatus bit of OLEMISC_RECOMPOSEONRESIZE
  2097.          * is set, then we need to run the object before calling
  2098.          * SetExtent to make sure it has a real chance to
  2099.          * re-render the object.  We have to update and close
  2100.          * the object as well after this happens.
  2101.          */
  2102.  
  2103.         if (OLEMISC_RECOMPOSEONRESIZE & m_grfMisc)
  2104.             {
  2105.             if (!OleIsRunning(m_pIOleObject))
  2106.                 {
  2107.                 OleRun(m_pIOleObject);
  2108.                 fRun=TRUE;
  2109.                 }
  2110.             }
  2111.  
  2112.         hr=m_pIOleObject->SetExtent(m_fe.dwAspect, &szl);
  2113.  
  2114.         /*
  2115.          * If the object is not running and it does not have
  2116.          * RECOMPOSEONRESIZE, then SetExtent fails.  Make
  2117.          * sure that we call SetExtent again (by just calling
  2118.          * SizeSet here again) when we next run the object.
  2119.          */
  2120.         if (SUCCEEDED(hr))
  2121.             {
  2122.             m_fSetExtent=FALSE;
  2123.  
  2124.             if (fRun)
  2125.                 {
  2126.                 m_pIOleObject->Update();
  2127.                 m_pIOleObject->Close(OLECLOSE_SAVEIFDIRTY);
  2128.                 }
  2129.             }
  2130.         else
  2131.             {
  2132.             if (OLE_E_NOTRUNNING==GetScode(hr))
  2133.                 m_fSetExtent=TRUE;
  2134.             }
  2135.         }
  2136.  
  2137.     return;
  2138.     }
  2139.  
  2140.  
  2141. void CTenant::RectGet(LPRECTL prcl, BOOL fDevice)
  2142.     {
  2143.     if (!fDevice)
  2144.         *prcl=m_rcl;
  2145.     else
  2146.         {
  2147.         RECT        rc;
  2148.  
  2149.         RECTFROMRECTL(rc, m_rcl);
  2150.         RectConvertMappings(&rc, NULL, TRUE);
  2151.         RECTLFROMRECT(*prcl, rc);
  2152.         }
  2153.  
  2154.     return;
  2155.     }
  2156.  
  2157.  
  2158. void CTenant::RectSet(LPRECTL prcl, BOOL fDevice, BOOL fInformObj)
  2159.     {
  2160.     SIZEL   szl;
  2161.     LONG    cx, cy;
  2162.  
  2163.     cx=m_rcl.right-m_rcl.left;
  2164.     cy=m_rcl.bottom-m_rcl.top;
  2165.  
  2166.     if (!fDevice)
  2167.         m_rcl=*prcl;
  2168.     else
  2169.         {
  2170.         RECT        rc;
  2171.  
  2172.         RECTFROMRECTL(rc, *prcl);
  2173.         RectConvertMappings(&rc, NULL, FALSE);
  2174.         RECTLFROMRECT(m_rcl, rc);
  2175.         }
  2176.  
  2177.     /*
  2178.      * Tell ourselves that the size changed, if it did.  SizeSet
  2179.      * will call IOleObject::SetExtent for us.
  2180.      */
  2181.     if ((m_rcl.right-m_rcl.left)!=cx || (m_rcl.bottom-m_rcl.top)!=cy)
  2182.         {
  2183.         SETSIZEL(szl, m_rcl.right-m_rcl.left, m_rcl.bottom-m_rcl.top);
  2184.         SizeSet(&szl, FALSE, fInformObj);
  2185.         }
  2186.  
  2187.     return;
  2188.     }
  2189.  
  2190.  
  2191.  
  2192.  
  2193.  
  2194.  
  2195.  
  2196. /*
  2197.  * CTenant::CreateStatic
  2198.  * (Protected)
  2199.  *
  2200.  * Purpose:
  2201.  *  Creates a new static bitmap or metafile object for this tenant
  2202.  *  using a freeloading method allowing us to specify exactly which
  2203.  *  type of data we want to paste since OleCreateStaticFromData
  2204.  *  doesn't.
  2205.  *
  2206.  * Parameters:
  2207.  *  pIDataObject    LPDATAOBJECT from which to paste.
  2208.  *  pFE             LPFORMATETC describing the format to paste.
  2209.  *  ppObj           LPUNKNOWN * into which we store the
  2210.  *                  object pointer.
  2211.  *
  2212.  * Return Value:
  2213.  *  HRESULT         NOERROR on success, error code otherwise.
  2214.  */
  2215.  
  2216. HRESULT CTenant::CreateStatic(LPDATAOBJECT pIDataObject
  2217.     , LPFORMATETC pFE, LPUNKNOWN *ppObj)
  2218.     {
  2219.     HRESULT             hr;
  2220.     STGMEDIUM           stm;
  2221.     LPUNKNOWN           pIUnknown;
  2222.     LPOLECACHE          pIOleCache;
  2223.     LPPERSISTSTORAGE    pIPersistStorage;
  2224.     CLSID               clsID;
  2225.  
  2226.     *ppObj=NULL;
  2227.  
  2228.     //Try to get the data desired as specified in pFE->cfFormat
  2229.     hr=pIDataObject->GetData(pFE, &stm);
  2230.  
  2231.     if (FAILED(hr))
  2232.         return hr;
  2233.  
  2234.     //Create the object to handle this data.
  2235.     if (CF_METAFILEPICT==pFE->cfFormat)
  2236.         clsID=CLSID_Picture_Metafile;
  2237.     else
  2238.         clsID=CLSID_Picture_Dib;
  2239.  
  2240.     hr=CreateDataCache(NULL, clsID, IID_IUnknown
  2241.         , (PPVOID)&pIUnknown);
  2242.  
  2243.     if (FAILED(hr))
  2244.         {
  2245.         ReleaseStgMedium(&stm);
  2246.         return hr;
  2247.         }
  2248.  
  2249.     m_clsID=clsID;
  2250.  
  2251.     //Stuff the data into the object
  2252.     pIUnknown->QueryInterface(IID_IPersistStorage
  2253.         , (PPVOID)&pIPersistStorage);
  2254.     pIPersistStorage->InitNew(m_pIStorage);
  2255.  
  2256.     //Now that we have the cache object, shove the data into it.
  2257.     pIUnknown->QueryInterface(IID_IOleCache, (PPVOID)&pIOleCache);
  2258.     pIOleCache->Cache(pFE, ADVF_PRIMEFIRST, NULL);
  2259.  
  2260.     hr=pIOleCache->SetData(pFE, &stm, TRUE);
  2261.     pIOleCache->Release();
  2262.  
  2263.     //Insure there is a persistent copy on the disk
  2264.     WriteClassStg(m_pIStorage, m_clsID);
  2265.     pIPersistStorage->Save(m_pIStorage, TRUE);
  2266.     pIPersistStorage->SaveCompleted(NULL);
  2267.     pIPersistStorage->Release();
  2268.  
  2269.     //The cache owns this now.
  2270.     ReleaseStgMedium(&stm);
  2271.  
  2272.     if (FAILED(hr))
  2273.         pIUnknown->Release();
  2274.     else
  2275.         *ppObj=pIUnknown;
  2276.  
  2277.     return hr;
  2278.     }
  2279.