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

Windows编程

开发平台:

Visual C++

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