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

Windows编程

开发平台:

Visual C++

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