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 / chap24 / patron / tenant.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  80KB  |  3,103 lines

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