TENANT.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:52k
源码类别:

Windows编程

开发平台:

Visual C++

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