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

Windows编程

开发平台:

Visual C++

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