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

Windows编程

开发平台:

Visual C++

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