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

  1. /*
  2.  * TENANT.CPP
  3.  * Patron Chapter 13
  4.  *
  5.  * Implementation of the CTentant class which holds information
  6.  * for a single object on a page.  It maintains position, references
  7.  * to data, and a storage.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15.  
  16.  
  17. #include "patron.h"
  18.  
  19.  
  20. /*
  21.  * CTenant::CTenant
  22.  * CTenant::~CTenant
  23.  *
  24.  * Constructor Parameters:
  25.  *  dwID            DWORD identifier for this page.
  26.  *  hWnd            HWND of the pages window.
  27.  *  pPG             PCPages to the parent structure.
  28.  */
  29.  
  30. CTenant::CTenant(DWORD dwID, HWND hWnd, PCPages pPG)
  31.     {
  32.     m_hWnd=hWnd;
  33.     m_dwID=dwID;
  34.  
  35.     m_fInitialized=0;
  36.     m_pIStorage=NULL;
  37.     m_cOpens=0;
  38.  
  39.     m_pObj=NULL;
  40.     m_pPG =pPG;
  41.     m_clsID=CLSID_NULL;
  42.     m_fSetExtent=FALSE;
  43.  
  44.     return;
  45.     }
  46.  
  47.  
  48. CTenant::~CTenant(void)
  49.     {
  50.     if (NULL!=m_pObj)
  51.         {
  52.         //We know we only hold one reference from Create or Load
  53.         m_pObj->Release();
  54.         m_pObj=NULL;
  55.         }
  56.  
  57.     return;
  58.     }
  59.  
  60.  
  61.  
  62. /*
  63.  * CTenant::GetID
  64.  *
  65.  * Return Value:
  66.  *  DWORD           dwID field in this tenant.
  67.  */
  68.  
  69. DWORD CTenant::GetID(void)
  70.     {
  71.     return m_dwID;
  72.     }
  73.  
  74.  
  75.  
  76. /*
  77.  * CTenant::GetStorageName
  78.  *
  79.  * Parameters:
  80.  *  pszName         LPOLESTR to a buffer in which to store the storage
  81.  *                  name for this tenant.
  82.  *
  83.  * Return Value:
  84.  *  UINT            Number of characters stored.
  85.  */
  86.  
  87. UINT CTenant::GetStorageName(LPOLESTR pszName)
  88.     {
  89.    #ifdef WIN32ANSI
  90.     char        szTemp[32];
  91.     UINT        cch;
  92.  
  93.     cch=wsprintf(szTemp, "Tenant %lu", m_dwID);
  94.     MultiByteToWideChar(CP_ACP, 0, szTemp, -1, pszName, 32);
  95.     return cch;
  96.    #else
  97.     return wsprintf(pszName, TEXT("Tenant %lu"), m_dwID);
  98.    #endif
  99.     }
  100.  
  101.  
  102.  
  103.  
  104.  
  105. /*
  106.  * CTenant::Create
  107.  *
  108.  * Purpose:
  109.  *  Creates a new tenant of the given CLSID, which can be either a
  110.  *  static bitmap or metafile now (Chapter 13) and which may
  111.  *  eventually be any compound document object.
  112.  *
  113.  * Parameters:
  114.  *  tType           TENANTTYPE to create, either a static metafile,
  115.  *                  bitmap, or some kind of compound document object
  116.  *                  This determines which OleCreate* call we use.
  117.  *  pvType          LPVOID providing the relevant pointer from which
  118.  *                  to create the tenant, depending on iType.
  119.  *  pFE             LPFORMATETC specifying the type of renderings
  120.  *                  to use.
  121.  *  pptl            PPOINTL in which we store offset coordinates.
  122.  *  pszl            LPSIZEL where this object should store its
  123.  *                  lometric extents.
  124.  *  pIStorage       LPSTORAGE of the page we live in.  We have to
  125.  *                  create another storage in this for the tenant.
  126.  *  ppo             PPATRONOBJECT containing placement data.
  127.  *  dwData          DWORD with extra data, sensitive to iType.
  128.  *
  129.  * Return Value:
  130.  *  UINT            A CREATE_* value depending on what we
  131.  *                  actually do.
  132.  */
  133.  
  134. UINT CTenant::Create(TENANTTYPE tType, LPVOID pvType
  135.     , LPFORMATETC pFE, PPOINTL pptl, LPSIZEL pszl
  136.     , LPSTORAGE pIStorage, PPATRONOBJECT ppo, DWORD dwData)
  137.     {
  138.     HRESULT         hr;
  139.     LPUNKNOWN       pObj;
  140.     LPVIEWOBJECT2   pIViewObject2;
  141.     LPOLEOBJECT     pIOleObject;
  142.     UINT            uRet=CREATE_GRAPHICONLY;
  143.  
  144.     if (NULL==pvType || NULL==pIStorage)
  145.         return CREATE_FAILED;
  146.  
  147.     //Fail if this is called for an already living tenant.
  148.     if (m_fInitialized)
  149.         return CREATE_FAILED;
  150.  
  151.     m_fInitialized=TRUE;
  152.  
  153.     //Create a new storage for this tenant.
  154.     if (!Open(pIStorage))
  155.         return CREATE_FAILED;
  156.  
  157.     /*
  158.      * Get the placement info if it's here.  We either have a non-
  159.      * NULL PPATRONOBJECT in ppo or we have to use default
  160.      * placement and retrieve the size from the object itself.
  161.      */
  162.     pszl->cx=0;
  163.     pszl->cy=0;
  164.  
  165.     if (NULL!=ppo)
  166.         {
  167.         *pFE=ppo->fe;
  168.         *pptl=ppo->ptl;
  169.         *pszl=ppo->szl;     //Could be 0,0 , so we ask object
  170.  
  171.         uRet=CREATE_PLACEDOBJECT;
  172.         }
  173.  
  174.     hr=ResultFromScode(E_FAIL);
  175.  
  176.     //Now create an object based specifically for the type.
  177.     switch (tType)
  178.         {
  179.         case TENANTTYPE_NULL:
  180.             break;
  181.  
  182.         case TENANTTYPE_STATIC:
  183.             /*
  184.              * We could use OleCreateStaticFromData here which does
  185.              * pretty much what we're doing below.  However, it does
  186.              * not allow us to control whether we paste a bitmap or
  187.              * a metafile--it uses metafile first, bitmap second.
  188.              * For this reason we'll use code developed in Chapter
  189.              * 11's FreeLoader to affect the paste.
  190.              */
  191.             hr=CreateStatic((LPDATAOBJECT)pvType, pFE, &pObj);
  192.             break;
  193.  
  194.         default:
  195.             break;
  196.         }
  197.  
  198.     //If creation didn't work, get rid of the element Open created.
  199.     if (FAILED(hr))
  200.         {
  201.         Destroy(pIStorage);
  202.         return CREATE_FAILED;
  203.         }
  204.  
  205.     //Otherwise, store the object pointer and initialize the tenant
  206.     m_pObj=pObj;
  207.     m_fe=*pFE;
  208.     m_fe.ptd=NULL;
  209.     m_dwState=TENANTSTATE_DEFAULT;
  210.  
  211.     //If we also saw PatronObjects on the clipboard, we have size
  212.  
  213.     if (0==pszl->cx && 0==pszl->cy)
  214.         {
  215.         SIZEL   szl;
  216.  
  217.         //Try to get the real size of the object, default to 2"*2"
  218.         SETSIZEL((*pszl), 2*LOMETRIC_PER_INCH, 2*LOMETRIC_PER_INCH);
  219.  
  220.         //Try IViewObject2 first, then IOleObject as a backup.
  221.         hr=pObj->QueryInterface(IID_IViewObject2
  222.             , (PPVOID)&pIViewObject2);
  223.  
  224.         if (SUCCEEDED(hr))
  225.             {
  226.             pIViewObject2->GetExtent(m_fe.dwAspect, -1, NULL, &szl);
  227.             pIViewObject2->Release();
  228.             }
  229.         else
  230.             {
  231.             hr=pObj->QueryInterface(IID_IOleObject
  232.                 , (PPVOID)&pIOleObject);
  233.  
  234.             if (SUCCEEDED(hr))
  235.                 {
  236.                 pIOleObject->GetExtent(m_fe.dwAspect, &szl);
  237.                 pIOleObject->Release();
  238.                 }
  239.             }
  240.  
  241.         if (SUCCEEDED(hr))
  242.             {
  243.             //Convert HIMETRIC to our LOMETRIC mapping
  244.             SETSIZEL((*pszl), szl.cx/10, szl.cy/10);
  245.             }
  246.         }
  247.  
  248.     return uRet;
  249.     }
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256. /*
  257.  * CTenant::Load
  258.  *
  259.  * Purpose:
  260.  *  Recreates the object living in this tenant in place of calling
  261.  *  FCreate.  This is used in loading as opposed to new creation.
  262.  *
  263.  * Parameters:
  264.  *  pIStorage       LPSTORAGE of the page we live in.
  265.  *  pti             PTENTANTINFO containing persistent information.
  266.  *                  The ID value in this structure is ignored.
  267.  *
  268.  * Return Value:
  269.  *  BOOL            TRUE if successful, FALSE otherwise.
  270.  */
  271.  
  272. BOOL CTenant::Load(LPSTORAGE pIStorage, PTENANTINFO pti)
  273.     {
  274.     HRESULT         hr;
  275.     LPUNKNOWN       pObj;
  276.  
  277.     if (NULL==pIStorage || NULL==pti)
  278.         return FALSE;
  279.  
  280.     //Fail if this is called for an already living tenant.
  281.     if (m_fInitialized)
  282.         return FALSE;
  283.  
  284.     m_fInitialized=TRUE;
  285.  
  286.     //Open the storage for this tenant.
  287.     if (!Open(pIStorage))
  288.         return FALSE;
  289.  
  290.     hr=OleLoad(m_pIStorage, IID_IUnknown, NULL, (PPVOID)&pObj);
  291.  
  292.     if (FAILED(hr))
  293.         {
  294.         Destroy(pIStorage);
  295.         return FALSE;
  296.         }
  297.  
  298.     //Otherwise, store the object pointer and initialize the tenant
  299.     m_pObj=pObj;
  300.     m_fe=pti->fe;
  301.     m_fe.ptd=NULL;
  302.     m_fSetExtent=pti->fSetExtent;
  303.     m_dwState=TENANTSTATE_DEFAULT;
  304.  
  305.     RectSet(&pti->rcl, FALSE);
  306.     return TRUE;
  307.     }
  308.  
  309.  
  310.  
  311.  
  312. /*
  313.  * CTenant::GetInfo
  314.  *
  315.  * Purpose:
  316.  *  Retrieved a TENANTINFO structure for this tenant.
  317.  *
  318.  * Parameters:
  319.  *  pti             PTENANTINFO structure to fill
  320.  *
  321.  * Return Value:
  322.  *  None
  323.  */
  324.  
  325. void CTenant::GetInfo(PTENANTINFO pti)
  326.     {
  327.     if (NULL!=pti)
  328.         {
  329.         pti->dwID=m_dwID;
  330.         pti->rcl=m_rcl;
  331.         pti->fe=m_fe;
  332.         pti->fSetExtent=m_fSetExtent;
  333.         }
  334.  
  335.     return;
  336.     }
  337.  
  338.  
  339.  
  340.  
  341.  
  342. /*
  343.  * CTenant::Open
  344.  *
  345.  * Purpose:
  346.  *  Retrieves the IStorage associated with this tenant.  The
  347.  *  IStorage is owned by the tenant and thus the tenant always
  348.  *  holds a reference count.
  349.  *
  350.  *  If the storage is already open for this tenant, then this
  351.  *  function will AddRef it; therefore the caller must always
  352.  *  match an Open with a Close.
  353.  *
  354.  * Parameters:
  355.  *  pIStorage       LPSTORAGE above this tenant (which has its
  356.  *                  own storage).
  357.  *
  358.  * Return Value:
  359.  *  BOOL            TRUE if opening succeeds, FALSE otherwise.
  360.  */
  361.  
  362. BOOL CTenant::Open(LPSTORAGE pIStorage)
  363.     {
  364.     HRESULT     hr=NOERROR;
  365.     DWORD       dwMode=STGM_TRANSACTED | STGM_READWRITE
  366.                     | STGM_SHARE_EXCLUSIVE;
  367.     OLECHAR     szTemp[32];
  368.  
  369.     if (NULL==m_pIStorage)
  370.         {
  371.         if (NULL==pIStorage)
  372.             return FALSE;
  373.  
  374.         /*
  375.          * Attempt to open the storage under this ID.  If there is
  376.          * none, then create it.  In either case we end up with an
  377.          * IStorage that we either save in pPage or release.
  378.          */
  379.  
  380.         GetStorageName(szTemp);
  381.         hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0
  382.             , &m_pIStorage);
  383.  
  384.         if (FAILED(hr))
  385.             {
  386.             hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0
  387.                 , &m_pIStorage);
  388.             }
  389.         }
  390.     else
  391.         m_pIStorage->AddRef();
  392.  
  393.     if (FAILED(hr))
  394.         return FALSE;
  395.  
  396.     m_cOpens++;
  397.     return TRUE;
  398.     }
  399.  
  400.  
  401.  
  402.  
  403. /*
  404.  * CTenant::Close
  405.  *
  406.  * Purpose:
  407.  *  Possibly commits the storage, then releases it reversing the
  408.  *  reference count from Open.  If the reference on the storage
  409.  *  goes to zero, the storage is forgotten.  However, the object we
  410.  *  contain is still held and as long as it's active the storage
  411.  *  remains alive.
  412.  *
  413.  * Parameters:
  414.  *  fCommit         BOOL indicating if we're to commit.
  415.  *
  416.  * Return Value:
  417.  *  None
  418.  */
  419.  
  420. void CTenant::Close(BOOL fCommit)
  421.     {
  422.     if (fCommit)
  423.         Update();
  424.  
  425.     if (NULL!=m_pIStorage)
  426.         {
  427.         m_pIStorage->Release();
  428.  
  429.         /*
  430.          * We can't use a zero reference count to know when to NULL
  431.          * this since other things might have AddRef'd the storage.
  432.          */
  433.         if (0==--m_cOpens)
  434.             m_pIStorage=NULL;
  435.         }
  436.  
  437.     return;
  438.     }
  439.  
  440.  
  441.  
  442.  
  443. /*
  444.  * CTenant::Update
  445.  *
  446.  * Purpose:
  447.  *  Forces a common on the page if it's open.
  448.  *
  449.  * Parameters:
  450.  *  None
  451.  *
  452.  * Return Value:
  453.  *  BOOL            TRUE if the object is open, FALSE otherwise.
  454.  */
  455.  
  456. BOOL CTenant::Update(void)
  457.     {
  458.     LPPERSISTSTORAGE    pIPS;
  459.  
  460.     if (NULL!=m_pIStorage)
  461.         {
  462.         /*
  463.          * We need to OleSave again because we might have changed
  464.          * the size or position of this tenant.  We also need to
  465.          * save the rectangle on the page, since that's not known
  466.          * to OLE.
  467.          */
  468.         m_pObj->QueryInterface(IID_IPersistStorage, (PPVOID)&pIPS);
  469.  
  470.         if (FAILED(OleSave(pIPS, m_pIStorage, TRUE)))
  471.             {
  472.             //This is essentially what OleSave does.
  473.             WriteClassStg(m_pIStorage, m_clsID);
  474.             pIPS->Save(m_pIStorage, TRUE);
  475.             }
  476.  
  477.         pIPS->SaveCompleted(NULL);
  478.         pIPS->Release();
  479.  
  480.         m_pIStorage->Commit(STGC_ONLYIFCURRENT);
  481.         }
  482.  
  483.     return FALSE;
  484.     }
  485.  
  486.  
  487.  
  488.  
  489.  
  490. /*
  491.  * CTenant::Destroy
  492.  *
  493.  * Purpose:
  494.  *  Removes this page from the given storage.  The caller should
  495.  *  eventually delete this CTenant object to free the object herein.
  496.  *  Nothing is committed when being destroyed.
  497.  *
  498.  * Parameters:
  499.  *  pIStorage       LPSTORAGE contianing this page on which to call
  500.  *                  DestroyElement
  501.  *
  502.  * Return Value:
  503.  *  None
  504.  */
  505.  
  506. void CTenant::Destroy(LPSTORAGE pIStorage)
  507.     {
  508.     OLECHAR     szTemp[32];
  509.  
  510.     if (NULL!=pIStorage)
  511.         {
  512.         if (NULL!=m_pIStorage)
  513.             {
  514.             //Remove all reference/open counts on this storage.
  515.             while (0!=m_cOpens)
  516.                 {
  517.                 m_pIStorage->Release();
  518.                 m_cOpens--;
  519.                 }
  520.             }
  521.  
  522.         GetStorageName(szTemp);
  523.         pIStorage->DestroyElement(szTemp);
  524.  
  525.         m_pIStorage=NULL;
  526.         }
  527.  
  528.     //m_pObj is released in destructor.
  529.     return;
  530.     }
  531.  
  532.  
  533.  
  534.  
  535. /*
  536.  * CTenant::Select
  537.  *
  538.  * Purpose:
  539.  *  Selects or deselects the tenant.
  540.  *
  541.  * Parameters:
  542.  *  fSelect         BOOL indicating the new state of the tenant.
  543.  *
  544.  * Return Value:
  545.  *  None
  546.  */
  547.  
  548. void CTenant::Select(BOOL fSelect)
  549.     {
  550.     BOOL        fWasSelected;
  551.     DWORD       dwState;
  552.     RECT        rc;
  553.     HDC         hDC;
  554.  
  555.     fWasSelected=(BOOL)(TENANTSTATE_SELECTED & m_dwState);
  556.  
  557.     //Nothing to do when there's no change.
  558.     if (fWasSelected==fSelect)
  559.         return;
  560.  
  561.     dwState=m_dwState & ~TENANTSTATE_SELECTED;
  562.     m_dwState=dwState | ((fSelect) ? TENANTSTATE_SELECTED : 0);
  563.  
  564.     /*
  565.      * Draw sizing handles to show the selection state.  We convert
  566.      * things to MM_TEXT since that's what this function expects.
  567.      */
  568.  
  569.     RECTFROMRECTL(rc, m_rcl);
  570.     RectConvertMappings(&rc, NULL, TRUE);
  571.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  572.  
  573.     hDC=GetDC(m_hWnd);
  574.  
  575.     UIDrawHandles(&rc, hDC, UI_HANDLES_INSIDE
  576.         | UI_HANDLES_NOBORDER | UI_HANDLES_USEINVERSE
  577.         , CXYHANDLE, !fWasSelected);
  578.  
  579.     ReleaseDC(m_hWnd, hDC);
  580.  
  581.     if (fSelect)
  582.         m_pPG->m_fDirty=TRUE;
  583.  
  584.     return;
  585.     }
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593. /*
  594.  * CTenant::Activate
  595.  *
  596.  * Purpose:
  597.  *  Activates a verb on the object living in the tenant.  Does
  598.  *  nothing for static objects.
  599.  *
  600.  * Parameters:
  601.  *  iVerb           LONG of the verb to execute.
  602.  *
  603.  * Return Value:
  604.  *  BOOL            TRUE if the object changed due to this verb
  605.  *                  execution.
  606.  */
  607.  
  608. BOOL CTenant::Activate(LONG iVerb)
  609.     {
  610.     MessageBeep(0); //Nothing doing for now.
  611.     return FALSE;
  612.     }
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619. /*
  620.  * CTenant::Draw
  621.  *
  622.  * Purpose:
  623.  *  Draws the tenant in its rectangle on the given hDC.  We assume
  624.  *  the DC is already set up for the mapping mode in which our
  625.  *  rectangle is expressed, since the Page we're in tells us both
  626.  *  the rect and the hDC.
  627.  *
  628.  * Parameters:
  629.  *  hDC             HDC in which to draw.  Could be a metafile,
  630.  *                  memory DC, screen, or printer.
  631.  *  ptd             DVTARGETDEVICE * describing the device.
  632.  *  hIC             HDC holding an information context (printing).
  633.  *  xOff, yOff      int offsets for the page in lometric
  634.  *  fNoColor        BOOL indicating if we should do B & W
  635.  *  fPrinter        BOOL indicating if we should render for a
  636.  *                  printer.
  637.  *
  638.  * Return Value:
  639.  *  None
  640.  */
  641.  
  642. void CTenant::Draw(HDC hDC, DVTARGETDEVICE *ptd, HDC hIC
  643.     , int xOff, int yOff, BOOL fNoColor, BOOL fPrinter)
  644.     {
  645.     HRESULT         hr;
  646.     RECT            rc;
  647.     RECTL           rcl;
  648.     UINT            uMM;
  649.     LPVIEWOBJECT2   pIViewObject2;
  650.  
  651.     hr=m_pObj->QueryInterface(IID_IViewObject2
  652.         , (PPVOID)&pIViewObject2);
  653.  
  654.     if (FAILED(hr))
  655.         return;
  656.  
  657.     RECTFROMRECTL(rc, m_rcl);
  658.     OffsetRect(&rc, -xOff, -yOff);
  659.     RECTLFROMRECT(rcl, rc);
  660.  
  661.     //We have to use Draw since we have a target device and IC.
  662.     hr=pIViewObject2->Draw(m_fe.dwAspect, -1, NULL, ptd, hIC, hDC
  663.         , &rcl, NULL, NULL, 0);
  664.     pIViewObject2->Release();
  665.  
  666.     /*
  667.      * If Draw failed, then perhaps it couldn't work for the device,
  668.      * so try good old OleDraw as a last resort.  The code will
  669.      * generally be OLE_E_BLANK.
  670.      */
  671.     if (FAILED(hr))
  672.         OleDraw(m_pObj, m_fe.dwAspect, hDC, &rc);
  673.  
  674.     if (!fPrinter && TENANTSTATE_SELECTED & m_dwState)
  675.         {
  676.         /*
  677.          * Draw sizing handles to show the selection state.  We
  678.          * convert things to MM_TEXT since that's what this
  679.          * function expects.
  680.          */
  681.         RectConvertMappings(&rc, NULL, TRUE);
  682.         uMM=SetMapMode(hDC, MM_TEXT);
  683.  
  684.         UIDrawHandles(&rc, hDC, UI_HANDLES_INSIDE
  685.             | UI_HANDLES_NOBORDER| UI_HANDLES_USEINVERSE
  686.             , CXYHANDLE, TRUE);
  687.  
  688.         uMM=SetMapMode(hDC, uMM);
  689.         }
  690.  
  691.     return;
  692.     }
  693.  
  694.  
  695.  
  696.  
  697.  
  698. /*
  699.  * CTenant::Repaint
  700.  * CTenant::Invalidate
  701.  *
  702.  * Purpose:
  703.  *  Repaints the tenant where it lies or invalidates its area
  704.  *  for later repainting.
  705.  *
  706.  * Parameters:
  707.  *  None
  708.  *
  709.  * Return Value:
  710.  *  None
  711.  */
  712.  
  713. void CTenant::Repaint(void)
  714.     {
  715.     RECT        rc;
  716.     HDC         hDC;
  717.  
  718.     hDC=GetDC(m_hWnd);
  719.     SetRect(&rc, m_pPG->m_xPos, m_pPG->m_yPos, 0, 0);
  720.     RectConvertMappings(&rc, NULL, FALSE);
  721.  
  722.     SetMapMode(hDC, MM_LOMETRIC);
  723.     Draw(hDC, NULL, NULL, rc.left, rc.top, FALSE, FALSE);
  724.  
  725.     ReleaseDC(m_hWnd, hDC);
  726.     return;
  727.     }
  728.  
  729.  
  730. void CTenant::Invalidate(void)
  731.     {
  732.     RECTL       rcl;
  733.     RECT        rc;
  734.  
  735.     RectGet(&rcl, TRUE);
  736.     RECTFROMRECTL(rc, rcl);
  737.  
  738.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  739.     InvalidateRect(m_hWnd, &rc, FALSE);
  740.  
  741.     return;
  742.     }
  743.  
  744.  
  745.  
  746.  
  747.  
  748.  
  749. /*
  750.  * CTenant::ObjectGet
  751.  *
  752.  * Purpose:
  753.  *  Retrieves the LPUNKNOWN of the object in use by this tenant
  754.  *
  755.  * Parameters:
  756.  *  ppUnk           LPUNKNOWN * in which to return the object
  757.  *                  pointer.
  758.  *
  759.  * Return Value:
  760.  *  None
  761.  */
  762.  
  763. void CTenant::ObjectGet(LPUNKNOWN *ppUnk)
  764.     {
  765.     if (NULL!=ppUnk)
  766.         {
  767.         *ppUnk=m_pObj;
  768.         m_pObj->AddRef();
  769.         }
  770.  
  771.     return;
  772.     }
  773.  
  774.  
  775.  
  776.  
  777.  
  778. /*
  779.  * CTenant::FormatEtcGet
  780.  *
  781.  * Purpose:
  782.  *  Retrieves the FORMATETC in use by this tenant
  783.  *
  784.  * Parameters:
  785.  *  pFE             LPFORMATETC in which to store the information.
  786.  *  fPresentation   BOOL indicating if we want the real format or
  787.  *                  that of the presentation.
  788.  *
  789.  * Return Value:
  790.  *  None
  791.  */
  792.  
  793. void CTenant::FormatEtcGet(LPFORMATETC pFE, BOOL fPresentation)
  794.     {
  795.     if (NULL!=pFE)
  796.         *pFE=m_fe;
  797.  
  798.     return;
  799.     }
  800.  
  801.  
  802.  
  803.  
  804.  
  805. /*
  806.  * CTenant::SizeGet
  807.  * CTenant::SizeSet
  808.  * CTenant::RectGet
  809.  * CTenant::RectSet
  810.  *
  811.  * Purpose:
  812.  *  Returns or sets the size/position of the object contained here.
  813.  *
  814.  * Parameters:
  815.  *  pszl/prcl       LPSIZEL (Size) or LPRECTL (Rect) with the
  816.  *                  extents of interest.  In Get situations,
  817.  *                  this will receive the extents; in Set it
  818.  *                  contains the extents.
  819.  *  fDevice         BOOL indicating that pszl/prcl is expressed
  820.  *                  in device units.  Otherwise it's LOMETRIC.
  821.  *
  822.  * Return Value:
  823.  *  None
  824.  */
  825.  
  826. void CTenant::SizeGet(LPSIZEL pszl, BOOL fDevice)
  827.     {
  828.     if (!fDevice)
  829.         {
  830.         pszl->cx=m_rcl.right-m_rcl.left;
  831.         pszl->cy=m_rcl.bottom-m_rcl.top;
  832.         }
  833.     else
  834.         {
  835.         RECT        rc;
  836.  
  837.         SetRect(&rc, (int)(m_rcl.right-m_rcl.left)
  838.             , (int)(m_rcl.bottom-m_rcl.top), 0, 0);
  839.  
  840.         RectConvertMappings(&rc, NULL, TRUE);
  841.  
  842.         pszl->cx=(long)rc.left;
  843.         pszl->cy=(long)rc.top;
  844.         }
  845.  
  846.     return;
  847.     }
  848.  
  849.  
  850. void CTenant::SizeSet(LPSIZEL pszl, BOOL fDevice)
  851.     {
  852.     SIZEL           szl;
  853.  
  854.     if (!fDevice)
  855.         {
  856.         szl=*pszl;
  857.         m_rcl.right =pszl->cx+m_rcl.left;
  858.         m_rcl.bottom=pszl->cy+m_rcl.top;
  859.         }
  860.     else
  861.         {
  862.         RECT        rc;
  863.  
  864.         SetRect(&rc, (int)pszl->cx, (int)pszl->cy, 0, 0);
  865.         RectConvertMappings(&rc, NULL, FALSE);
  866.  
  867.         m_rcl.right =(long)rc.left+m_rcl.left;
  868.         m_rcl.bottom=(long)rc.top+m_rcl.top;
  869.  
  870.         SETSIZEL(szl, (long)rc.left, (long)rc.top);
  871.         }
  872.  
  873.  
  874.     //Tell OLE that this object was resized.
  875.     if (NULL!=m_pObj)
  876.         {
  877.         HRESULT     hr;
  878.         LPOLEOBJECT pIOleObject;
  879.  
  880.         hr=m_pObj->QueryInterface(IID_IOleObject
  881.             , (PPVOID)&pIOleObject);
  882.  
  883.         if (SUCCEEDED(hr))
  884.             {
  885.             //Convert our LOMETRIC into HIMETRIC by *=10
  886.             szl.cx*=10;
  887.             szl.cy*=-10;    //Our size is stored negative.
  888.  
  889.             pIOleObject->SetExtent(m_fe.dwAspect, &szl);
  890.             pIOleObject->Release();
  891.             }
  892.         }
  893.  
  894.     return;
  895.     }
  896.  
  897.  
  898. void CTenant::RectGet(LPRECTL prcl, BOOL fDevice)
  899.     {
  900.     if (!fDevice)
  901.         *prcl=m_rcl;
  902.     else
  903.         {
  904.         RECT        rc;
  905.  
  906.         RECTFROMRECTL(rc, m_rcl);
  907.         RectConvertMappings(&rc, NULL, TRUE);
  908.         RECTLFROMRECT(*prcl, rc);
  909.         }
  910.  
  911.     return;
  912.     }
  913.  
  914.  
  915. void CTenant::RectSet(LPRECTL prcl, BOOL fDevice)
  916.     {
  917.     SIZEL   szl;
  918.     LONG    cx, cy;
  919.  
  920.     cx=m_rcl.right-m_rcl.left;
  921.     cy=m_rcl.bottom-m_rcl.top;
  922.  
  923.     if (!fDevice)
  924.         m_rcl=*prcl;
  925.     else
  926.         {
  927.         RECT        rc;
  928.  
  929.         RECTFROMRECTL(rc, *prcl);
  930.         RectConvertMappings(&rc, NULL, FALSE);
  931.         RECTLFROMRECT(m_rcl, rc);
  932.         }
  933.  
  934.     //Tell ourselves that the size changed, if it did.
  935.     if ((m_rcl.right-m_rcl.left)!=cx || (m_rcl.bottom-m_rcl.top)!=cy)
  936.         {
  937.         SETSIZEL(szl, m_rcl.right-m_rcl.left, m_rcl.bottom-m_rcl.top);
  938.         SizeSet(&szl, FALSE);
  939.         }
  940.  
  941.     return;
  942.     }
  943.  
  944.  
  945.  
  946.  
  947.  
  948.  
  949.  
  950. /*
  951.  * CTenant::CreateStatic
  952.  * (Protected)
  953.  *
  954.  * Purpose:
  955.  *  Creates a new static bitmap or metafile object for this tenant
  956.  *  using a freeloading method allowing us to specify exactly which
  957.  *  type of data we want to paste since OleCreateStaticFromData
  958.  *  doesn't.
  959.  *
  960.  * Parameters:
  961.  *  pIDataObject    LPDATAOBJECT from which to paste.
  962.  *  pFE             LPFORMATETC describing the format to paste.
  963.  *  ppObj           LPUNKNOWN * into which we store the
  964.  *                  object pointer.
  965.  *
  966.  * Return Value:
  967.  *  HRESULT         NOERROR on success, error code otherwise.
  968.  */
  969.  
  970. HRESULT CTenant::CreateStatic(LPDATAOBJECT pIDataObject
  971.     , LPFORMATETC pFE, LPUNKNOWN *ppObj)
  972.     {
  973.     HRESULT             hr;
  974.     STGMEDIUM           stm;
  975.     LPUNKNOWN           pIUnknown;
  976.     LPOLECACHE          pIOleCache;
  977.     LPPERSISTSTORAGE    pIPersistStorage;
  978.     CLSID               clsID;
  979.  
  980.     *ppObj=NULL;
  981.  
  982.     //Try to get the data desired as specified in pFE->cfFormat
  983.     hr=pIDataObject->GetData(pFE, &stm);
  984.  
  985.     if (FAILED(hr))
  986.         return hr;
  987.  
  988.     //Create the object to handle this data.
  989.     if (CF_METAFILEPICT==pFE->cfFormat)
  990.         clsID=CLSID_Picture_Metafile;
  991.     else
  992.         clsID=CLSID_Picture_Dib;
  993.  
  994.     hr=CreateDataCache(NULL, clsID, IID_IUnknown
  995.         , (PPVOID)&pIUnknown);
  996.  
  997.     if (FAILED(hr))
  998.         {
  999.         ReleaseStgMedium(&stm);
  1000.         return hr;
  1001.         }
  1002.  
  1003.     m_clsID=clsID;
  1004.  
  1005.     //Stuff the data into the object
  1006.     pIUnknown->QueryInterface(IID_IPersistStorage
  1007.         , (PPVOID)&pIPersistStorage);
  1008.     pIPersistStorage->InitNew(m_pIStorage);
  1009.  
  1010.     //Now that we have the cache object, shove the data into it.
  1011.     pIUnknown->QueryInterface(IID_IOleCache, (PPVOID)&pIOleCache);
  1012.     pIOleCache->Cache(pFE, ADVF_PRIMEFIRST, NULL);
  1013.  
  1014.     hr=pIOleCache->SetData(pFE, &stm, TRUE);
  1015.     pIOleCache->Release();
  1016.  
  1017.     //Insure there is a persistent copy on the disk
  1018.     WriteClassStg(m_pIStorage, m_clsID);
  1019.     pIPersistStorage->Save(m_pIStorage, TRUE);
  1020.     pIPersistStorage->SaveCompleted(NULL);
  1021.     pIPersistStorage->Release();
  1022.  
  1023.     //The cache owns this now.
  1024.     ReleaseStgMedium(&stm);
  1025.  
  1026.     if (FAILED(hr))
  1027.         pIUnknown->Release();
  1028.     else
  1029.         *ppObj=pIUnknown;
  1030.  
  1031.     return hr;
  1032.     }
  1033.