home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap22 / patron / tenant.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  64KB  |  2,532 lines

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