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 / chap12 / patron / page.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  22KB  |  963 lines

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