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 / page.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  21.5 KB  |  952 lines

  1. /*
  2.  * PAGE.CPP
  3.  * Patron Chapter 13
  4.  *
  5.  * Implementation of parts of the CPage class; those member
  6.  * functions dealing with mouse events are in PAGEMOUS.CPP.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "patron.h"
  17.  
  18.  
  19. /*
  20.  * CPage::CPage
  21.  * CPage::~CPage
  22.  *
  23.  * Constructor Parameters:
  24.  *  dwID            DWORD identifier for this page.
  25.  *  hWnd            HWND of the pages window (for repaints, etc).
  26.  *  pPG             PCPages to the Pages window.
  27.  */
  28.  
  29. CPage::CPage(DWORD dwID, HWND hWnd, PCPages pPG)
  30.     {
  31.     m_dwID     =dwID;
  32.     m_pIStorage=NULL;
  33.  
  34.     m_cOpens=0;
  35.     m_hWnd=hWnd;
  36.     m_pPG=pPG;
  37.  
  38.     m_dwIDNext      =0;
  39.     m_cTenants      =0;
  40.     m_hWndTenantList=NULL;
  41.     m_iTenantCur    =NOVALUE;   //Tenants are zero indexed.
  42.     m_pTenantCur    =NULL;
  43.  
  44.     m_uHTCode=HTNOWHERE;
  45.     m_uSizingFlags=0;
  46.     m_fTracking=FALSE;
  47.     m_hDC=NULL;
  48.  
  49.     //CHAPTER13MOD
  50.     m_fDragPending=FALSE;
  51.     //End CHAPTER13MOD
  52.     m_fSizePending=FALSE;
  53.     m_fTimer=FALSE;
  54.  
  55.     //CHAPTER13MOD
  56.     //Get WIN.INI distance and delay values, with OLE defaults.
  57.     m_cxyDist=GetProfileInt(TEXT("windows"), TEXT("DragMinDist")
  58.         , DD_DEFDRAGMINDIST);
  59.     m_cDelay=GetProfileInt(TEXT("windows"), TEXT("DragDelay")
  60.         , DD_DEFDRAGDELAY);
  61.     //End CHAPTER13MOD
  62.     return;
  63.     }
  64.  
  65.  
  66. CPage::~CPage(void)
  67.     {
  68.     if (m_fTimer)
  69.         KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  70.  
  71.     m_hWnd=NULL;
  72.     Close(FALSE);
  73.     return;
  74.     }
  75.  
  76.  
  77.  
  78. /*
  79.  * CPage::GetID
  80.  *
  81.  * Return Value:
  82.  *  DWORD           dwID field in this page.
  83.  */
  84.  
  85. DWORD CPage::GetID(void)
  86.     {
  87.     return m_dwID;
  88.     }
  89.  
  90.  
  91.  
  92.  
  93.  
  94. /*
  95.  * CPage::Open
  96.  *
  97.  * Purpose:
  98.  *  Retrieves the IStorage associated with this page.  The IStorage
  99.  *  is owned by the page and thus the page always holds a reference
  100.  *  count.  The caller should call Close or delete this page to
  101.  *  match this open.
  102.  *
  103.  *  This function may be called multiple times resulting in
  104.  *  additional reference counts on the storage each of which must be
  105.  *  matched with a call to Close.  The last Close can be done
  106.  *  through delete.
  107.  *
  108.  * Parameters:
  109.  *  pIStorage       LPSTORAGE in which this page lives.
  110.  *
  111.  * Return Value:
  112.  *  BOOL            TRUE if opening succeeds, FALSE otherwise.
  113.  */
  114.  
  115. BOOL CPage::Open(LPSTORAGE pIStorage)
  116.     {
  117.     HRESULT         hr=NOERROR;
  118.     LPSTREAM        pIStream;
  119.     DWORD           dwMode;
  120.     OLECHAR         szTemp[32];
  121.     BOOL            fNew;
  122.     BOOL            fCreated=FALSE;
  123.     TENANTLIST      tl;
  124.     PTENANTINFO     pti;
  125.     ULONG           cb;
  126.     LPMALLOC        pIMalloc;
  127.     UINT            i;
  128.     PCTenant        pTenant;
  129.  
  130.     fNew=(NULL==m_pIStorage);
  131.  
  132.     if (!fNew)
  133.         {
  134.         m_cOpens++;
  135.         m_pIStorage->AddRef();
  136.         return TRUE;
  137.         }
  138.  
  139.     if (NULL==pIStorage)
  140.         return FALSE;
  141.  
  142.     /*
  143.      * Attempt to open the storage under this ID.  If none,
  144.      * create one.  In either case, the IStorage is either
  145.      * saved in pPage or released.
  146.      */
  147.  
  148.     GetStorageName(szTemp);
  149.     dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  150.  
  151.     hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0
  152.         , &m_pIStorage);
  153.  
  154.     if (FAILED(hr))
  155.         {
  156.         hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0
  157.             , &m_pIStorage);
  158.         fCreated=TRUE;
  159.         }
  160.  
  161.     if (FAILED(hr))
  162.         return FALSE;
  163.  
  164.     m_cOpens++;
  165.  
  166.     if (NULL==m_hWndTenantList)
  167.         {
  168.         /*
  169.          * The first time we open this page, create the hidden
  170.          * listbox we'll use to track tenants.  We give it the
  171.          * owner-draw style so we can just store pointers in it.
  172.          */
  173.         m_hWndTenantList=CreateWindow(TEXT("listbox")
  174.             , TEXT("Tenant List"), WS_POPUP | LBS_OWNERDRAWFIXED
  175.             , 0, 0, 100, 100, HWND_DESKTOP, NULL
  176.             , m_pPG->m_hInst, NULL);
  177.  
  178.         if (NULL==m_hWndTenantList)
  179.             return FALSE;
  180.         }
  181.  
  182.  
  183.     //If this is brand-new, we're done.
  184.     if (fCreated)
  185.         return TRUE;
  186.  
  187.  
  188.     /*
  189.      * Now open the stream we saved in Close and load all the
  190.      * tenants listed in there.  If there are none, then we don't
  191.      * have to load squat.
  192.      */
  193.  
  194.     hr=m_pIStorage->OpenStream(SZSTREAMTENANTLIST, NULL, STGM_DIRECT
  195.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  196.  
  197.     if (FAILED(hr))
  198.         return FALSE;
  199.  
  200.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  201.         {
  202.         pIStream->Read(&tl, sizeof(tl), NULL);
  203.         m_cTenants=tl.cTenants;
  204.         m_dwIDNext=tl.dwIDNext;
  205.         m_iTenantCur=0;
  206.  
  207.         cb=tl.cTenants*sizeof(TENANTINFO);
  208.  
  209.         if (0!=cb)
  210.             {
  211.             pti=(PTENANTINFO)pIMalloc->Alloc(cb);
  212.  
  213.             if (NULL!=pti)
  214.                 {
  215.                 pIStream->Read(pti, cb, NULL);
  216.  
  217.                 for (i=0; i < m_cTenants; i++)
  218.                     {
  219.                     if (TenantAdd(NOVALUE, (pti+i)->dwID, &pTenant))
  220.                         pTenant->Load(m_pIStorage, (pti+i));
  221.                     }
  222.  
  223.                 pIMalloc->Free(pti);
  224.                 }
  225.             }
  226.  
  227.         pIMalloc->Release();
  228.         }
  229.  
  230.     pIStream->Release();
  231.  
  232.     //Get and select the first tenant
  233.     if (TenantGet(0, &m_pTenantCur, FALSE))
  234.         m_pTenantCur->Select(TRUE);
  235.  
  236.     return TRUE;
  237.     }
  238.  
  239.  
  240.  
  241.  
  242.  
  243. /*
  244.  * CPage::Close
  245.  *
  246.  * Purpose:
  247.  *  Possibly commits the storage, then releases it reversing the
  248.  *  reference count from Open.
  249.  *
  250.  * Parameters:
  251.  *  fCommit         BOOL indicating if we're to commit.
  252.  *
  253.  * Return Value:
  254.  *  None
  255.  */
  256.  
  257. void CPage::Close(BOOL fCommit)
  258.     {
  259.     if (NULL==m_pIStorage)
  260.         return;
  261.  
  262.     if (fCommit)
  263.         Update();
  264.  
  265.     m_pIStorage->Release();
  266.  
  267.     //If this was the last close, make all tenants loaded->passive
  268.     if (0==--m_cOpens)
  269.         {
  270.         UINT        i;
  271.         PCTenant    pTenant;
  272.  
  273.         m_pIStorage=NULL;
  274.  
  275.         for (i=0; i < m_cTenants; i++)
  276.             {
  277.             if (TenantGet(i, &pTenant, FALSE))
  278.                 {
  279.                 if (NULL!=m_hWnd)
  280.                     {
  281.                     //Open may select again, so this repaints.
  282.                     pTenant->Select(FALSE);
  283.                     }
  284.  
  285.                 pTenant->Close(FALSE);
  286.                 delete pTenant;
  287.                 }
  288.             }
  289.  
  290.         DestroyWindow(m_hWndTenantList);
  291.         m_hWndTenantList=NULL;
  292.         }
  293.  
  294.     return;
  295.     }
  296.  
  297.  
  298.  
  299.  
  300. /*
  301.  * CPage::Update
  302.  *
  303.  * Purpose:
  304.  *  Forces a common on the page if it's open.
  305.  *
  306.  * Parameters:
  307.  *  None
  308.  *
  309.  * Return Value:
  310.  *  BOOL            TRUE if there are any open objects on this page,
  311.  *                  that is, we should remain open.
  312.  */
  313.  
  314. BOOL CPage::Update(void)
  315.     {
  316.     BOOL            fOpen=FALSE;
  317.     UINT            i;
  318.     PCTenant        pTenant;
  319.     HRESULT         hr;
  320.     LPSTREAM        pIStream;
  321.     TENANTLIST      tl;
  322.     PTENANTINFO     pti;
  323.     ULONG           cb;
  324.     LPMALLOC        pIMalloc;
  325.  
  326.     //Walk the list of objects and update them all as well.
  327.     for (i=0; i < m_cTenants; i++)
  328.         {
  329.         if (TenantGet(i, &pTenant, FALSE))
  330.             fOpen |= pTenant->Update();
  331.         }
  332.  
  333.     //Now write our own stream containing the tenant list.
  334.     hr=m_pIStorage->CreateStream(SZSTREAMTENANTLIST, STGM_CREATE
  335.         | STGM_WRITE| STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, 0
  336.         , &pIStream);
  337.  
  338.     if (FAILED(hr))
  339.         return fOpen;
  340.  
  341.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  342.         {
  343.         tl.cTenants=m_cTenants;
  344.         tl.dwIDNext=m_dwIDNext;
  345.  
  346.         pIStream->Write(&tl, sizeof(TENANTLIST), &cb);
  347.  
  348.         cb=m_cTenants*sizeof(TENANTINFO);
  349.         pti=(PTENANTINFO)pIMalloc->Alloc(cb);
  350.  
  351.         if (NULL!=pti)
  352.             {
  353.             for (i=0; i < m_cTenants; i++)
  354.                 {
  355.                 TenantGet(i, &pTenant, FALSE);
  356.                 pTenant->GetInfo((pti+i));
  357.                 }
  358.  
  359.             pIStream->Write(pti, cb, &cb);
  360.             pIMalloc->Free(pti);
  361.             }
  362.  
  363.         pIMalloc->Release();
  364.         }
  365.  
  366.     pIStream->Release();
  367.  
  368.     //Now commit the whole mess and we're done
  369.     if (NULL!=m_pIStorage)
  370.         m_pIStorage->Commit(STGC_DEFAULT);
  371.  
  372.     return fOpen;
  373.     }
  374.  
  375.  
  376.  
  377.  
  378.  
  379. /*
  380.  * CPage::Destroy
  381.  *
  382.  * Purpose:
  383.  *  Removes this page from the given storage.  The caller should
  384.  *  eventually delete this Page object to free the storage.
  385.  *
  386.  * Parameters:
  387.  *  pIStorage       LPSTORAGE contianing this page on which to call
  388.  *                  DestroyElement
  389.  *
  390.  * Return Value:
  391.  *  None
  392.  */
  393.  
  394. void CPage::Destroy(LPSTORAGE pIStorage)
  395.     {
  396.     if (NULL!=pIStorage)
  397.         {
  398.         OLECHAR szTemp[32];
  399.  
  400.         Close(FALSE);
  401.         GetStorageName(szTemp);
  402.         pIStorage->DestroyElement(szTemp);
  403.         }
  404.  
  405.     return;
  406.     }
  407.  
  408.  
  409.  
  410.  
  411. /*
  412.  * CPage::GetStorageName
  413.  *
  414.  * Parameters:
  415.  *  pszName         LPOLESTR to a buffer in which to store the
  416.  *                  storage name for this page.
  417.  *
  418.  * Return Value:
  419.  *  UINT            Number of characters stored.
  420.  */
  421.  
  422. UINT CPage::GetStorageName(LPOLESTR pszName)
  423.     {
  424.    #ifdef WIN32ANSI
  425.     char        szTemp[32];
  426.     UINT        cch;
  427.  
  428.     cch=wsprintf(szTemp, "Page %lu", m_dwID);
  429.     MultiByteToWideChar(CP_ACP, 0, szTemp, -1, pszName, 32);
  430.     return cch;
  431.    #else
  432.     return wsprintf(pszName, TEXT("Page %lu"), m_dwID);
  433.    #endif
  434.     }
  435.  
  436.  
  437.  
  438.  
  439. /*
  440.  * CPage::Draw
  441.  *
  442.  * Purpose:
  443.  *  Draws the objects on this page to the given hDC.
  444.  *
  445.  * Parameters:
  446.  *  hDC             HDC on which to draw.
  447.  *  xOff, yOff      int offsets for the page.
  448.  *  fNoColor        BOOL indicating black & white screen rendering.
  449.  *  fPrinter        BOOL indicating hDC is on the printer.
  450.  *
  451.  * Return Value:
  452.  *  None
  453.  */
  454.  
  455. void CPage::Draw(HDC hDC, int xOff, int yOff, BOOL fNoColor
  456.     , BOOL fPrinter)
  457.     {
  458.     int                 i;
  459.     PCTenant            pTenant;
  460.     HDC                 hIC=NULL;
  461.     PCOMBINEDEVICE      pcd=NULL;
  462.     DVTARGETDEVICE     *ptd=NULL;
  463.  
  464.     /*
  465.      * If printing, tell the tenant to forget the borders. Otherwise
  466.      * we leave xOff and yOff the same to account for scrolling.
  467.      */
  468.     if (fPrinter)
  469.         {
  470.         xOff=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  471.         yOff=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  472.  
  473.         /*
  474.          * Get device information.  If this fails, ptd is
  475.          * NULL which is acceptable.
  476.          */
  477.         if (m_pPG->DevReadConfig(&pcd, &hIC))
  478.             ptd=&(pcd->td);
  479.         }
  480.  
  481.     for (i=(int)m_cTenants-1; i >=0; i--)
  482.         {
  483.         if (TenantGet(i, &pTenant, FALSE))
  484.             {
  485.             RECT        rc, rcWin;
  486.             RECTL       rcl;
  487.  
  488.             //Paint this tenant only if visible.
  489.             pTenant->RectGet(&rcl, TRUE);
  490.             RECTFROMRECTL(rc, rcl);
  491.             OffsetRect(&rc, -(int)m_pPG->m_xPos
  492.                 , -(int)m_pPG->m_yPos);
  493.             GetClientRect(m_hWnd, &rcWin);
  494.  
  495.             if (IntersectRect(&rc, &rc, &rcWin))
  496.                 {
  497.                 pTenant->Draw(hDC, ptd, hIC, xOff, yOff
  498.                     , fNoColor, fPrinter);
  499.                 }
  500.             }
  501.         }
  502.  
  503.     //Free whatever CPages::DevReadConfig returned.
  504.     if (NULL!=pcd)
  505.         {
  506.         LPMALLOC    pIMalloc;
  507.  
  508.         if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  509.             {
  510.             pIMalloc->Free(pcd);
  511.             pIMalloc->Release();
  512.             }
  513.         }
  514.  
  515.     if (NULL!=hIC)
  516.         DeleteDC(hIC);
  517.  
  518.     return;
  519.     }
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526. /*
  527.  * CPage::TenantCreate
  528.  *
  529.  * Purpose:
  530.  *  Creates a new tenant of a specific type.
  531.  *
  532.  * Parameters:
  533.  *  tType           TENANTTYPE to create.
  534.  *  pv              LPVOID providing information for the new
  535.  *                  object creation.
  536.  *  pFE             LPFORMATETC describing how we want this
  537.  *                  rendered.
  538.  *  ppo             PPATRONOBJECT with placement data.
  539.  *  dwData          DWORD extra data to pass to the tenant.
  540.  *
  541.  * Return Value:
  542.  *  None
  543.  */
  544.  
  545. BOOL CPage::TenantCreate(TENANTTYPE tType, LPVOID pv
  546.     , LPFORMATETC pFE, PPATRONOBJECT ppo, DWORD dwData)
  547.     {
  548.     PCTenant    pTenant;
  549.     UINT        uRet;
  550.     int         x, y;
  551.     int         h, v;
  552.     POINTL      ptl;
  553.     SIZEL       szl;
  554.     RECTL       rcl;
  555.     RECT        rc;
  556.  
  557.     //New tenants go at top of the pile; zero index to TenantAdd.
  558.     if (!TenantAdd(0, m_dwIDNext, &pTenant))
  559.         return FALSE;
  560.  
  561.     uRet=pTenant->Create(tType, pv, pFE, &ptl, &szl, m_pIStorage
  562.         , ppo, dwData);
  563.  
  564.     if (CREATE_FAILED==uRet)
  565.         {
  566.         //Reverse Create AND TenantAdd
  567.         SendMessage(m_hWndTenantList, LB_DELETESTRING, 0, 0L);
  568.         pTenant->Destroy(m_pIStorage);
  569.  
  570.         delete pTenant;
  571.         return FALSE;
  572.         }
  573.  
  574.     m_dwIDNext++;
  575.     m_cTenants++;
  576.  
  577.     if (NULL!=m_pTenantCur)
  578.         m_pTenantCur->Select(FALSE);
  579.  
  580.     m_iTenantCur=0;             //First one in the list now.
  581.     m_pTenantCur=pTenant;
  582.  
  583.     //Tell the tenant where it lives, default is (0,0) in print area
  584.     x=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  585.     y=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  586.  
  587.     h=x;
  588.     v=y;
  589.  
  590.     if (CREATE_PLACEDOBJECT==uRet)
  591.         {
  592.         SetRect(&rc, 3*CXYHANDLE, 3*CXYHANDLE, 0, 0);
  593.         RectConvertMappings(&rc, NULL, FALSE);
  594.  
  595.         //Make sure place point is on page, otherwise go to (0,0)
  596.         if (((int)ptl.x > x)
  597.             && ((int)ptl.x < x+(int)m_pPG->m_cx-rc.left))
  598.             x=(int)ptl.x;
  599.  
  600.         //m_pPG->m_cy is absolute
  601.         if (((int)ptl.y < y)
  602.             && ((int)ptl.y > y-(int)m_pPG->m_cy-rc.top))
  603.             y=(int)ptl.y;
  604.         }
  605.  
  606.     //Bounds check size of the object and fit to page as necessary.
  607.     if (x+(int)szl.cx > (int)(h+m_pPG->m_cx))
  608.         szl.cx=h+m_pPG->m_cx-x;
  609.  
  610.     //Remember that szl we get from Create is absolute
  611.     if (y-(int)szl.cy < (int)(v-m_pPG->m_cy))
  612.         szl.cy=-(int)(v-m_pPG->m_cy-y);
  613.  
  614.     SETRECTL(rcl, x, y, x+szl.cx, y-szl.cy);
  615.     m_pTenantCur->RectSet(&rcl, FALSE);
  616.  
  617.     //Force a repaint on this new guy
  618.     m_pTenantCur->Invalidate();
  619.     UpdateWindow(m_hWnd);
  620.  
  621.     m_pTenantCur->Select(TRUE);
  622.     return TRUE;
  623.     }
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630. /*
  631.  * CPage::TenantDestroy
  632.  *
  633.  * Purpose:
  634.  *  Destroys the currently selected tenant on this page.
  635.  *
  636.  * Parameters:
  637.  *  None
  638.  *
  639.  * Return Value:
  640.  *  None
  641.  */
  642.  
  643. BOOL CPage::TenantDestroy(void)
  644.     {
  645.     if (NULL==m_pTenantCur)
  646.         {
  647.         MessageBeep(0);
  648.         return FALSE;
  649.         }
  650.  
  651.     SendMessage(m_hWndTenantList, LB_DELETESTRING
  652.         , m_iTenantCur, 0L);
  653.  
  654.     m_pTenantCur->Invalidate();
  655.     m_pTenantCur->Destroy(m_pIStorage);
  656.  
  657.     delete m_pTenantCur;
  658.     m_pTenantCur=NULL;
  659.  
  660.     //Update counts, etc., and select the next tenant in the list.
  661.     if (m_iTenantCur==m_cTenants-1)
  662.         m_iTenantCur--;
  663.  
  664.     if (0==--m_cTenants)
  665.         m_pTenantCur=NULL;
  666.     else
  667.         {
  668.         TenantGet(m_iTenantCur, &m_pTenantCur, TRUE);
  669.         m_pTenantCur->Select(TRUE);
  670.         }
  671.  
  672.     UpdateWindow(m_hWnd);
  673.     return TRUE;
  674.     }
  675.  
  676.  
  677.  
  678.  
  679.  
  680. /*
  681.  * CPage::TenantClip
  682.  *
  683.  * Purpose:
  684.  *  Copies or cuts the currently selected tenant to the clipoard.
  685.  *
  686.  * Parameters:
  687.  *  fCut            BOOL TRUE to cut the object, FALSE to copy.
  688.  *
  689.  * Return Value:
  690.  *  BOOL            TRUE if successful, FALSE otherwise.
  691.  */
  692.  
  693. BOOL CPage::TenantClip(BOOL fCut)
  694.     {
  695.     LPDATAOBJECT    pIDataObject;
  696.     BOOL            fRet=FALSE;
  697.  
  698.     if (NULL==m_pTenantCur)
  699.         return FALSE;
  700.  
  701.     /*
  702.      * To perform a data transfer operation, we need to create a
  703.      * data object with the selected object's data inside. To do
  704.      * this we CoCreateInstance on CLSID_DataTransferObject
  705.      * (Also implemented in this chapter), retrieve data from the
  706.      * object we have, stuff that data into the transfer object,
  707.      * then stick that object on the clipboard.
  708.      *
  709.      * Since we'll want an identical object at other times, like for
  710.      * drag-drop, we use a private function to actually create it.
  711.      */
  712.  
  713.     pIDataObject=TransferObjectCreate(NULL);
  714.  
  715.     if (NULL!=pIDataObject)
  716.         {
  717.         if (SUCCEEDED(OleSetClipboard(pIDataObject)))
  718.             {
  719.             if (fCut)
  720.                 TenantDestroy();
  721.  
  722.             fRet=TRUE;
  723.             }
  724.  
  725.         pIDataObject->Release();
  726.         }
  727.  
  728.     return fRet;
  729.     }
  730.  
  731.  
  732.  
  733.  
  734.  
  735. /*
  736.  * CPage::FQueryObjectSelected
  737.  *
  738.  * Purpose:
  739.  *  Returns whether or not there is an object selected on this
  740.  *  page for Cut, Copy, Delete functions.
  741.  *
  742.  * Parameters:
  743.  *  hMenu           HMENU of the Edit menu.
  744.  *
  745.  * Return Value:
  746.  *  BOOL            TRUE if we have an object, FALSE otherwise.
  747.  */
  748.  
  749. BOOL CPage::FQueryObjectSelected(HMENU hMenu)
  750.     {
  751.     return (NULL!=m_pTenantCur);
  752.     }
  753.  
  754.  
  755.  
  756.  
  757.  
  758.  
  759. /*
  760.  * CPage::TenantGet
  761.  * (Protected)
  762.  *
  763.  * Purpose:
  764.  *  Returns a tenant of a given index returning a BOOL so it's
  765.  *  simple to use this function inside if statements.
  766.  *
  767.  * Parameters:
  768.  *  iTenant         UINT tenant to retrieve 0 based.
  769.  *  ppTenant        PCPage * in which to return the tenant
  770.  *                  pointer
  771.  *  fOpen           BOOL indicating if we should open this
  772.  *                  tenant as well.
  773.  *
  774.  * Return Value:
  775.  *  BOOL            TRUE if successful, FALSE otherwise.
  776.  */
  777.  
  778. BOOL CPage::TenantGet(UINT iTenant, PCTenant *ppTenant
  779.     , BOOL fOpen)
  780.     {
  781.     if (NULL==ppTenant)
  782.         return FALSE;
  783.  
  784.     if (LB_ERR!=SendMessage(m_hWndTenantList, LB_GETTEXT
  785.         , iTenant, (LONG)ppTenant))
  786.         {
  787.         if (fOpen)
  788.             (*ppTenant)->Open(m_pIStorage);
  789.  
  790.         return TRUE;
  791.         }
  792.  
  793.     return FALSE;
  794.     }
  795.  
  796.  
  797.  
  798.  
  799.  
  800.  
  801.  
  802. /*
  803.  * CPage::TenantAdd
  804.  * (Protected)
  805.  *
  806.  * Purpose:
  807.  *  Creates a new tenant initialized to the given values.  The new
  808.  *  tenants's storage is created if it does not already exist.  If
  809.  *  fOpenStorage is set the the tenants's storage is opened and left
  810.  *  opened.
  811.  *
  812.  * Parameters:
  813.  *  iTenant         UINT Location at which to insert tenant; new
  814.  *                  tenant is inserted after this position.  NOVALUE
  815.  *                  for the end.
  816.  *  dwID            DWORD ID for this tenant.
  817.  *  ppNew           PCTenant * in which to store the new tenant.
  818.  *
  819.  * Return Value:
  820.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  821.  */
  822.  
  823. BOOL CPage::TenantAdd(UINT iTenant, DWORD dwID
  824.     , PCTenant *ppNew)
  825.     {
  826.     PCTenant    pTenant;
  827.     LRESULT     lr;
  828.  
  829.     if (NULL!=ppNew)
  830.         *ppNew=NULL;
  831.  
  832.     pTenant=new CTenant(dwID, m_hWnd, m_pPG);
  833.  
  834.     if (NULL==pTenant)
  835.         return FALSE;
  836.  
  837.     //Now try to add to the listbox.
  838.     lr=SendMessage(m_hWndTenantList, LB_INSERTSTRING, iTenant
  839.         , (LONG)pTenant);
  840.  
  841.     if (lr < 0)
  842.         {
  843.         delete pTenant;
  844.         return FALSE;
  845.         }
  846.  
  847.     *ppNew=pTenant;
  848.     return TRUE;
  849.     }
  850.  
  851.  
  852.  
  853.  
  854.  
  855. /*
  856.  * CPage::TransferObjectCreate
  857.  * (Protected)
  858.  *
  859.  * Purpose:
  860.  *  Creates a DataTransferObject and stuff the current selection's
  861.  *  data into it.
  862.  *
  863.  * Parameters:
  864.  *  pptl            PPOINTL containing the pick point in device
  865.  *                  units applicable only to drag-drop; since
  866.  *                  drag-drop is inherently mouse oriented, we use
  867.  *                  device units for the point.  Ignored if NULL.
  868.  *
  869.  * Return Value:
  870.  *  LPDATAOBJECT    Pointer to the object created, NULL on failure
  871.  */
  872.  
  873. LPDATAOBJECT CPage::TransferObjectCreate(PPOINTL pptl)
  874.     {
  875.     LPDATAOBJECT    pIDataObject;
  876.     LPDATAOBJECT    pIDataT;
  877.     PPATRONOBJECT   ppo;
  878.     RECTL           rcl;
  879.     LPUNKNOWN       pObj;
  880.     FORMATETC       fe;
  881.     STGMEDIUM       stm;
  882.     HRESULT         hr;
  883.  
  884.     m_pTenantCur->ObjectGet(&pObj);
  885.  
  886.     hr=CoCreateInstance(CLSID_DataTransferObject, NULL
  887.         , CLSCTX_INPROC_SERVER, IID_IDataObject
  888.         , (PPVOID)&pIDataObject);
  889.  
  890.     if (FAILED(hr))
  891.         return NULL;
  892.  
  893.     //Go get the data we should hold on to.
  894.     hr=pObj->QueryInterface(IID_IDataObject, (PPVOID)&pIDataT);
  895.  
  896.     if (FAILED(hr))
  897.         {
  898.         pIDataObject->Release();
  899.         pObj->Release();
  900.         return NULL;
  901.         }
  902.  
  903.     //Copy from known obj into transfer obj.  Ordering is important!
  904.  
  905.     //Generate placeable object structure
  906.     stm.tymed=TYMED_HGLOBAL;
  907.     stm.pUnkForRelease=NULL;
  908.     stm.hGlobal=GlobalAlloc(GHND, sizeof(PATRONOBJECT));
  909.  
  910.     if (NULL==stm.hGlobal)
  911.         {
  912.         pIDataObject->Release();
  913.         pObj->Release();
  914.         return NULL;
  915.         }
  916.  
  917.     ppo=(PPATRONOBJECT)GlobalLock(stm.hGlobal);
  918.  
  919.     m_pTenantCur->SizeGet(&ppo->szl, FALSE);
  920.     ppo->szl.cy=-ppo->szl.cy; //Negate to make absolute size
  921.  
  922.     m_pTenantCur->RectGet(&rcl, FALSE);
  923.     ppo->ptl.x=rcl.left;
  924.     ppo->ptl.y=rcl.top;
  925.  
  926.     if (NULL==pptl)
  927.         {
  928.         ppo->ptlPick.x=0;
  929.         ppo->ptlPick.y=0;
  930.         }
  931.     else
  932.         ppo->ptlPick=*pptl;
  933.  
  934.     m_pTenantCur->FormatEtcGet(&ppo->fe, FALSE);
  935.  
  936.     GlobalUnlock(stm.hGlobal);
  937.  
  938.     SETDefFormatEtc(fe, m_pPG->m_cf, TYMED_HGLOBAL);
  939.     pIDataObject->SetData(&fe, &stm, TRUE);
  940.  
  941.  
  942.     //Copy the actual presentation.
  943.     m_pTenantCur->FormatEtcGet(&fe, TRUE);
  944.     pIDataT->GetData(&fe, &stm);
  945.     pIDataObject->SetData(&fe, &stm, TRUE);
  946.  
  947.     pIDataT->Release();
  948.  
  949.     pObj->Release();
  950.     return pIDataObject;    //Caller now responsible
  951.     }
  952.