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

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