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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * PAGE.CPP
  3.  * Patron Chapter 20
  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.     //CHAPTER20MOD
  49.     m_fReopen=FALSE;
  50.     //End CHAPTER20MOD
  51.     return;
  52.     }
  53. CPage::~CPage(void)
  54.     {
  55.     if (m_fTimer)
  56.         KillTimer(m_hWnd, IDTIMER_DEBOUNCE);
  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.     HRESULT                 hr=NOERROR;
  94.     LPSTREAM                pIStream;
  95.     DWORD                   dwMode;
  96.     OLECHAR                 szTemp[32];
  97.     TCHAR                   szCap[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.     //CHAPTER20MOD
  107.     UINT                    cLinks;
  108.     LPOLELINK               pIOleLink;
  109.     LPUNKNOWN               pIUnknown;
  110.     UINT                    uRet;
  111.     OLEUIEDITLINKS          el;
  112.     PCIOleUILinkContainer   pIUILinks;
  113.     HWND                    hWndDoc;
  114.     //End CHAPTER20MOD
  115.     fNew=(NULL==m_pIStorage);
  116.     if (!fNew)
  117.         {
  118.         m_cOpens++;
  119.         m_pIStorage->AddRef();
  120.         return TRUE;
  121.         }
  122.     if (NULL==pIStorage)
  123.         return FALSE;
  124.     /*
  125.      * Attempt to open the storage under this ID.  If none,
  126.      * create one.  In either case, the IStorage is either
  127.      * saved in pPage or released.
  128.      */
  129.     GetStorageName(szTemp);
  130.     dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  131.     hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0
  132.         , &m_pIStorage);
  133.     if (FAILED(hr))
  134.         {
  135.         hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0
  136.             , &m_pIStorage);
  137.         fCreated=TRUE;
  138.         }
  139.     if (FAILED(hr))
  140.         return FALSE;
  141.     m_cOpens++;
  142.     if (NULL==m_hWndTenantList)
  143.         {
  144.         /*
  145.          * The first time we open this page, create the hidden
  146.          * listbox we'll use to track tenants.  We give it the
  147.          * owner-draw style so we can just store pointers in it.
  148.          */
  149.         m_hWndTenantList=CreateWindow(TEXT("listbox")
  150.             , TEXT("Tenant List"), WS_POPUP | LBS_OWNERDRAWFIXED
  151.             , 0, 0, 100, 100, HWND_DESKTOP, NULL
  152.             , m_pPG->m_hInst, NULL);
  153.         if (NULL==m_hWndTenantList)
  154.             return FALSE;
  155.         }
  156.     //If this is brand-new, we're done.
  157.     if (fCreated)
  158.         return TRUE;
  159.     /*
  160.      * Now open the stream we saved in Close and load all the
  161.      * tenants listed in there.  If there are none, then we don't
  162.      * have to load squat.
  163.      */
  164.     hr=m_pIStorage->OpenStream(SZSTREAMTENANTLIST, NULL, STGM_DIRECT
  165.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  166.     if (FAILED(hr))
  167.         return FALSE;
  168.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  169.         {
  170.         pIStream->Read(&tl, sizeof(tl), NULL);
  171.         m_cTenants=tl.cTenants;
  172.         m_dwIDNext=tl.dwIDNext;
  173.         m_iTenantCur=0;
  174.         cb=tl.cTenants*sizeof(TENANTINFO);
  175.         if (0!=cb)
  176.             {
  177.             pti=(PTENANTINFO)pIMalloc->Alloc(cb);
  178.             if (NULL!=pti)
  179.                 {
  180.                 pIStream->Read(pti, cb, NULL);
  181.                 for (i=0; i < m_cTenants; i++)
  182.                     {
  183.                     if (TenantAdd(NOVALUE, (pti+i)->dwID, &pTenant))
  184.                         {
  185.                         pTenant->Load(m_pIStorage, (pti+i));
  186.                         //CHAPTER20MOD
  187.                         //Make sure it knows about the show state.
  188.                         pTenant->ShowObjectType(m_pPG->m_fShowTypes);
  189.                         //End CHAPTER20MOD
  190.                         }
  191.                     }
  192.                 pIMalloc->Free(pti);
  193.                 }
  194.             }
  195.         pIMalloc->Release();
  196.         }
  197.     pIStream->Release();
  198.     //Get and select the first tenant
  199.     if (TenantGet(0, &m_pTenantCur, FALSE))
  200.         m_pTenantCur->Select(TRUE);
  201.     //CHAPTER20MOD
  202.     //If we just saved and closed, don't bother with updating links
  203.     if (m_fReopen)
  204.         {
  205.         m_fReopen=FALSE;
  206.         return TRUE;
  207.         }
  208.     /*
  209.      * Update all the links in this page, showing the progress
  210.      * indicator as it's happening.  We use the same
  211.      * IOlUILinkContainer implementation as we do for the links
  212.      * dialog, passing it to OleUIUpdateLinks which does everything
  213.      * for us.
  214.      *
  215.      * We might also optimize this to not do anything if there are
  216.      * no automatic links, but it's not a big concern.
  217.      */
  218.     //First, count the number of automatic links.
  219.     cLinks=0;
  220.     for (i=0; i < m_cTenants; i++)
  221.         {
  222.         if (TenantGet(i, &pTenant, FALSE))
  223.             {
  224.             DWORD       dw;
  225.             pTenant->ObjectGet(&pIUnknown);
  226.             hr=pIUnknown->QueryInterface(IID_IOleLink
  227.                 , (PPVOID)&pIOleLink);
  228.             pIUnknown->Release();
  229.             if (FAILED(hr))
  230.                 continue;
  231.             pIOleLink->GetUpdateOptions(&dw);
  232.             pIOleLink->Release();
  233.             if (OLEUPDATE_ALWAYS==dw)
  234.                 cLinks++;
  235.             }
  236.         }
  237.     //If we have any automatic links, invoke the update dialog.
  238.     if (0==cLinks)
  239.         return TRUE;
  240.     //Create an IOleUILinkContainer instantiation.
  241.     if (!m_pPG->GetUILinkContainer(&pIUILinks))
  242.         return TRUE;    //Guess we can't update, oh well.
  243.     hWndDoc=GetParent(m_hWnd);
  244.     LoadString(m_pPG->m_hInst, IDS_CAPTION, szCap, sizeof(szCap));
  245.     if (!OleUIUpdateLinks(pIUILinks, hWndDoc, szCap, cLinks))
  246.         {
  247.         /*
  248.          * If updating failed, ask to show the links dialog.  NOTE:
  249.          * OleUIPromptUser has a variable wsprintf argument list
  250.          * after the hWnd parameter!  Use appropriate typecasting!
  251.          */
  252.         uRet=OleUIPromptUser(IDD_CANNOTUPDATELINK, hWndDoc, szCap);
  253.        #ifdef IDC_PU_LINKS
  254.         if (IDC_PU_LINKS==uRet)
  255.        #else
  256.         if (ID_PU_LINKS==uRet)      //Win3.1
  257.        #endif
  258.             {
  259.             //Throw up the links dialog.
  260.             memset(&el, 0, sizeof(el));
  261.             el.cbStruct=sizeof(el);
  262.             el.hWndOwner=hWndDoc;
  263.             el.lpOleUILinkContainer=pIUILinks;
  264.             OleUIEditLinks(&el);
  265.             }
  266.         }
  267.     m_pPG->m_fDirty=pIUILinks->m_fDirty;
  268.     pIUILinks->Release();
  269.     //End CHAPTER20MOD
  270.     return TRUE;
  271.     }
  272. /*
  273.  * CPage::Close
  274.  *
  275.  * Purpose:
  276.  *  Possibly commits the storage, then releases it reversing the
  277.  *  reference count from Open.
  278.  *
  279.  * Parameters:
  280.  *  fCommit         BOOL indicating if we're to commit.
  281.  *
  282.  * Return Value:
  283.  *  None
  284.  */
  285. void CPage::Close(BOOL fCommit)
  286.     {
  287.     if (NULL==m_pIStorage)
  288.         return;
  289.     if (fCommit)
  290.         Update();
  291.     m_pIStorage->Release();
  292.     //If this was the last close, make all tenants loaded->passive
  293.     if (0==--m_cOpens)
  294.         {
  295.         UINT        i;
  296.         PCTenant    pTenant;
  297.         m_pIStorage=NULL;
  298.         for (i=0; i < m_cTenants; i++)
  299.             {
  300.             if (TenantGet(i, &pTenant, FALSE))
  301.                 {
  302.                 if (NULL!=m_hWnd)
  303.                     {
  304.                     //Open may select again, so this repaints.
  305.                     pTenant->Select(FALSE);
  306.                     }
  307.                 pTenant->Close(FALSE);
  308.                 pTenant->Release();
  309.                 }
  310.             }
  311.         DestroyWindow(m_hWndTenantList);
  312.         m_hWndTenantList=NULL;
  313.         //CHAPTER20MOD
  314.         /*
  315.          * If we reopen this page right away, this flag will tell
  316.          * us to skip updating links again which would make us
  317.          * dirty right after a SaveAs operation.
  318.          */
  319.         m_fReopen=TRUE;
  320.         //End CHAPTER20MOD
  321.         }
  322.     return;
  323.     }
  324. /*
  325.  * CPage::Update
  326.  *
  327.  * Purpose:
  328.  *  Forces a common on the page if it's open.
  329.  *
  330.  * Parameters:
  331.  *  None
  332.  *
  333.  * Return Value:
  334.  *  BOOL            TRUE if there are any open objects on this page,
  335.  *                  that is, we should remain open.
  336.  */
  337. BOOL CPage::Update(void)
  338.     {
  339.     BOOL            fOpen=FALSE;
  340.     UINT            i;
  341.     PCTenant        pTenant;
  342.     HRESULT         hr;
  343.     LPSTREAM        pIStream;
  344.     TENANTLIST      tl;
  345.     PTENANTINFO     pti;
  346.     ULONG           cb;
  347.     LPMALLOC        pIMalloc;
  348.     //Walk the list of objects and update them all as well.
  349.     for (i=0; i < m_cTenants; i++)
  350.         {
  351.         if (TenantGet(i, &pTenant, FALSE))
  352.             fOpen |= pTenant->Update();
  353.         }
  354.     //Now write our own stream containing the tenant list.
  355.     hr=m_pIStorage->CreateStream(SZSTREAMTENANTLIST, STGM_CREATE
  356.         | STGM_WRITE| STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, 0
  357.         , &pIStream);
  358.     if (FAILED(hr))
  359.         return fOpen;
  360.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  361.         {
  362.         tl.cTenants=m_cTenants;
  363.         tl.dwIDNext=m_dwIDNext;
  364.         pIStream->Write(&tl, sizeof(TENANTLIST), &cb);
  365.         cb=m_cTenants*sizeof(TENANTINFO);
  366.         pti=(PTENANTINFO)pIMalloc->Alloc(cb);
  367.         if (NULL!=pti)
  368.             {
  369.             for (i=0; i < m_cTenants; i++)
  370.                 {
  371.                 TenantGet(i, &pTenant, FALSE);
  372.                 pTenant->GetInfo((pti+i));
  373.                 }
  374.             pIStream->Write(pti, cb, &cb);
  375.             pIMalloc->Free(pti);
  376.             }
  377.         pIMalloc->Release();
  378.         }
  379.     pIStream->Release();
  380.     //Now commit the whole mess and we're done
  381.     if (NULL!=m_pIStorage)
  382.         m_pIStorage->Commit(STGC_DEFAULT);
  383.     return fOpen;
  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. void CPage::Destroy(LPSTORAGE pIStorage)
  400.     {
  401.     if (NULL!=pIStorage)
  402.         {
  403.         OLECHAR szTemp[32];
  404.         Close(FALSE);
  405.         GetStorageName(szTemp);
  406.         pIStorage->DestroyElement(szTemp);
  407.         }
  408.     return;
  409.     }
  410. /*
  411.  * CPage::GetStorageName
  412.  *
  413.  * Parameters:
  414.  *  pszName         LPOLESTR to a buffer in which to store the
  415.  *                  storage name for this page.
  416.  *
  417.  * Return Value:
  418.  *  UINT            Number of characters stored.
  419.  */
  420. UINT CPage::GetStorageName(LPOLESTR pszName)
  421.     {
  422.    #ifdef WIN32ANSI
  423.     char        szTemp[32];
  424.     UINT        cch;
  425.     cch=wsprintf(szTemp, "Page %lu", m_dwID);
  426.     MultiByteToWideChar(CP_ACP, 0, szTemp, -1, pszName, 32);
  427.     return cch;
  428.    #else
  429.     return wsprintf(pszName, TEXT("Page %lu"), m_dwID);
  430.    #endif
  431.     }
  432. /*
  433.  * CPage::Draw
  434.  *
  435.  * Purpose:
  436.  *  Draws the objects on this page to the given hDC.
  437.  *
  438.  * Parameters:
  439.  *  hDC             HDC on which to draw.
  440.  *  xOff, yOff      int offsets for the page.
  441.  *  fNoColor        BOOL indicating black & white screen rendering.
  442.  *  fPrinter        BOOL indicating hDC is on the printer.
  443.  *
  444.  * Return Value:
  445.  *  None
  446.  */
  447. void CPage::Draw(HDC hDC, int xOff, int yOff, BOOL fNoColor
  448.     , BOOL fPrinter)
  449.     {
  450.     int                 i;
  451.     PCTenant            pTenant;
  452.     HDC                 hIC=NULL;
  453.     PCOMBINEDEVICE      pcd=NULL;
  454.     DVTARGETDEVICE     *ptd=NULL;
  455.     /*
  456.      * If printing, tell the tenant to forget the borders. Otherwise
  457.      * we leave xOff and yOff the same to account for scrolling.
  458.      */
  459.     if (fPrinter)
  460.         {
  461.         xOff=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  462.         yOff=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  463.         /*
  464.          * Get device information.  If this fails, ptd is
  465.          * NULL which is acceptable.
  466.          */
  467.         if (m_pPG->DevReadConfig(&pcd, &hIC))
  468.             ptd=&(pcd->td);
  469.         }
  470.     for (i=(int)m_cTenants-1; i >=0; i--)
  471.         {
  472.         if (TenantGet(i, &pTenant, FALSE))
  473.             {
  474.             RECT        rc, rcWin;
  475.             RECTL       rcl;
  476.             //Paint this tenant only if visible.
  477.             pTenant->RectGet(&rcl, TRUE);
  478.             RECTFROMRECTL(rc, rcl);
  479.             OffsetRect(&rc, -(int)m_pPG->m_xPos
  480.                 , -(int)m_pPG->m_yPos);
  481.             GetClientRect(m_hWnd, &rcWin);
  482.             if (IntersectRect(&rc, &rc, &rcWin))
  483.                 {
  484.                 pTenant->Draw(hDC, ptd, hIC, xOff, yOff
  485.                     , fNoColor, fPrinter);
  486.                 }
  487.             }
  488.         }
  489.     //Free whatever CPages::DevReadConfig returned.
  490.     if (NULL!=pcd)
  491.         {
  492.         LPMALLOC    pIMalloc;
  493.         if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  494.             {
  495.             pIMalloc->Free(pcd);
  496.             pIMalloc->Release();
  497.             }
  498.         }
  499.     if (NULL!=hIC)
  500.         DeleteDC(hIC);
  501.     return;
  502.     }
  503. /*
  504.  * CPage::TenantCreate
  505.  *
  506.  * Purpose:
  507.  *  Creates a new tenant of a specific type.
  508.  *
  509.  * Parameters:
  510.  *  tType           TENANTTYPE to create.
  511.  *  pv              LPVOID providing information for the new
  512.  *                  object creation.
  513.  *  pFE             LPFORMATETC describing how we want this
  514.  *                  rendered.
  515.  *  ppo             PPATRONOBJECT with placement data.
  516.  *  dwData          DWORD extra data to pass to the tenant.
  517.  *
  518.  * Return Value:
  519.  *  None
  520.  */
  521. BOOL CPage::TenantCreate(TENANTTYPE tType, LPVOID pv
  522.     , LPFORMATETC pFE, PPATRONOBJECT ppo, DWORD dwData)
  523.     {
  524.     PCTenant    pTenant;
  525.     UINT        uRet;
  526.     int         x, y;
  527.     int         h, v;
  528.     POINTL      ptl;
  529.     SIZEL       szl;
  530.     RECTL       rcl;
  531.     RECT        rc;
  532.     //New tenants go at top of the pile; zero index to TenantAdd.
  533.     if (!TenantAdd(0, m_dwIDNext, &pTenant))
  534.         return FALSE;
  535.     uRet=pTenant->Create(tType, pv, pFE, &ptl, &szl, m_pIStorage
  536.         , ppo, dwData);
  537.     if (CREATE_FAILED==uRet)
  538.         {
  539.         //Reverse Create AND TenantAdd
  540.         SendMessage(m_hWndTenantList, LB_DELETESTRING, 0, 0L);
  541.         pTenant->Destroy(m_pIStorage);
  542.         pTenant->Release();
  543.         return FALSE;
  544.         }
  545.     m_dwIDNext++;
  546.     m_cTenants++;
  547.     if (NULL!=m_pTenantCur)
  548.         m_pTenantCur->Select(FALSE);
  549.     m_iTenantCur=0;             //First one in the list now.
  550.     m_pTenantCur=pTenant;
  551.     //Tell the tenant where it lives, default is (0,0) in print area
  552.     x=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  553.     y=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  554.     h=x;
  555.     v=y;
  556.     if (CREATE_PLACEDOBJECT==uRet)
  557.         {
  558.         SetRect(&rc, 3*CXYHANDLE, 3*CXYHANDLE, 0, 0);
  559.         RectConvertMappings(&rc, NULL, FALSE);
  560.         //Make sure place point is on page, otherwise go to (0,0)
  561.         if (((int)ptl.x > x)
  562.             && ((int)ptl.x < x+(int)m_pPG->m_cx-rc.left))
  563.             x=(int)ptl.x;
  564.         //m_pPG->m_cy is absolute
  565.         if (((int)ptl.y < y)
  566.             && ((int)ptl.y > y-(int)m_pPG->m_cy-rc.top))
  567.             y=(int)ptl.y;
  568.         }
  569.     //Bounds check size of the object and fit to page as necessary.
  570.     if (x+(int)szl.cx > (int)(h+m_pPG->m_cx))
  571.         szl.cx=h+m_pPG->m_cx-x;
  572.     //Remember that szl we get from Create is absolute
  573.     if (y-(int)szl.cy < (int)(v-m_pPG->m_cy))
  574.         szl.cy=-(int)(v-m_pPG->m_cy-y);
  575.     SETRECTL(rcl, x, y, x+szl.cx, y-szl.cy);
  576.     m_pTenantCur->RectSet(&rcl, FALSE, TRUE);
  577.     //Force a repaint on this new guy
  578.     m_pTenantCur->Invalidate();
  579.     UpdateWindow(m_hWnd);
  580.     m_pTenantCur->Select(TRUE);
  581.     //CHAPTER20MOD
  582.     //Make sure this new tenant knows about showing it's type.
  583.     m_pTenantCur->ShowObjectType(m_pPG->m_fShowTypes);
  584.     //End CHAPTER20MOD
  585.     //Activate new objects immediately and force a save on them
  586.     if (TENANTTYPE_EMBEDDEDOBJECT==tType)
  587.         {
  588.         m_pTenantCur->Activate(OLEIVERB_SHOW);
  589.         m_pTenantCur->Update();
  590.         }
  591.     return TRUE;
  592.     }
  593. /*
  594.  * CPage::TenantDestroy
  595.  *
  596.  * Purpose:
  597.  *  Destroys the currently selected tenant on this page.
  598.  *
  599.  * Parameters:
  600.  *  None
  601.  *
  602.  * Return Value:
  603.  *  None
  604.  */
  605. BOOL CPage::TenantDestroy(void)
  606.     {
  607.     if (NULL==m_pTenantCur)
  608.         {
  609.         MessageBeep(0);
  610.         return FALSE;
  611.         }
  612.     SendMessage(m_hWndTenantList, LB_DELETESTRING
  613.         , m_iTenantCur, 0L);
  614.     m_pTenantCur->Invalidate();
  615.     m_pTenantCur->Destroy(m_pIStorage);
  616.     m_pTenantCur->Release();
  617.     m_pTenantCur=NULL;
  618.     //Update counts, etc., and select the next tenant in the list.
  619.     if (m_iTenantCur==m_cTenants-1)
  620.         m_iTenantCur--;
  621.     if (0==--m_cTenants)
  622.         m_pTenantCur=NULL;
  623.     else
  624.         {
  625.         TenantGet(m_iTenantCur, &m_pTenantCur, TRUE);
  626.         m_pTenantCur->Select(TRUE);
  627.         }
  628.     UpdateWindow(m_hWnd);
  629.     return TRUE;
  630.     }
  631. /*
  632.  * CPage::TenantClip
  633.  *
  634.  * Purpose:
  635.  *  Copies or cuts the currently selected tenant to the clipoard.
  636.  *
  637.  * Parameters:
  638.  *  fCut            BOOL TRUE to cut the object, FALSE to copy.
  639.  *
  640.  * Return Value:
  641.  *  BOOL            TRUE if successful, FALSE otherwise.
  642.  */
  643. BOOL CPage::TenantClip(BOOL fCut)
  644.     {
  645.     LPDATAOBJECT    pIDataObject;
  646.     BOOL            fRet=FALSE;
  647.     if (NULL==m_pTenantCur)
  648.         return FALSE;
  649.     /*
  650.      * To perform a data transfer operation, we need to create a
  651.      * data object with the selected object's data inside. To do
  652.      * this we CoCreateInstance on CLSID_DataTransferObject
  653.      * (Also implemented in this chapter), retrieve data from the
  654.      * object we have, stuff that data into the transfer object,
  655.      * then stick that object on the clipboard.
  656.      *
  657.      * Since we'll want an identical object at other times, like for
  658.      * drag-drop, we use a private function to actually create it.
  659.      */
  660.     pIDataObject=TransferObjectCreate(NULL);
  661.     if (NULL!=pIDataObject)
  662.         {
  663.         if (SUCCEEDED(OleSetClipboard(pIDataObject)))
  664.             {
  665.             if (fCut)
  666.                 TenantDestroy();
  667.             fRet=TRUE;
  668.             }
  669.         pIDataObject->Release();
  670.         }
  671.     return fRet;
  672.     }
  673. /*
  674.  * CPage::FQueryObjectSelected
  675.  *
  676.  * Purpose:
  677.  *  Returns whether or not there is an object selected on this
  678.  *  page for Cut, Copy, Delete functions.
  679.  *
  680.  * Parameters:
  681.  *  hMenu           HMENU of the Edit menu.
  682.  *
  683.  * Return Value:
  684.  *  BOOL            TRUE if we have an object, FALSE otherwise.
  685.  */
  686. BOOL CPage::FQueryObjectSelected(HMENU hMenu)
  687.     {
  688.     HMENU       hMenuTemp;
  689.     /*
  690.      * This will only be called on WM_INITMENUPOPUP, we'll also
  691.      * use this function to create the Verb menu for this object.
  692.      */
  693.     if (NULL!=m_pTenantCur)
  694.         {
  695.         m_pTenantCur->AddVerbMenu(hMenu, MENUPOS_OBJECT);
  696.         return TRUE;
  697.         }
  698.     OleUIAddVerbMenu(NULL, NULL, hMenu, MENUPOS_OBJECT
  699.         , IDM_VERBMIN, IDM_VERBMAX, FALSE, 0, &hMenuTemp);
  700.     return FALSE;
  701.     }
  702. /*
  703.  * CPage::ActivateObject
  704.  *
  705.  * Purpose:
  706.  *  Executes a verb on the currently selected object.
  707.  *
  708.  * Parameters:
  709.  *  iVerb           LONG of the selected verb.
  710.  *
  711.  * Return Value:
  712.  *  None
  713.  */
  714. void CPage::ActivateObject(LONG iVerb)
  715.     {
  716.     if (NULL==m_pTenantCur)
  717.         return;
  718.     m_pTenantCur->Activate(iVerb);
  719.     return;
  720.     }
  721. //CHAPTER20MOD
  722. /*
  723.  * CPage::ShowObjectTypes
  724.  *
  725.  * Purpose:
  726.  *  Loops through all the tenants and tells each one to turn on or
  727.  *  off the Show Objects features.
  728.  *
  729.  * Parameters:
  730.  *  fShow           BOOL indicating to show the type or not.
  731.  *
  732.  * Return Value:
  733.  *  None
  734.  */
  735. void CPage::ShowObjectTypes(BOOL fShow)
  736.     {
  737.     PCTenant    pTenant;
  738.     UINT        i;
  739.     for (i=0; i < m_cTenants; i++)
  740.         {
  741.         if (TenantGet(i, &pTenant, FALSE))
  742.             pTenant->ShowObjectType(fShow);
  743.         }
  744.     return;
  745.     }
  746. /*
  747.  * CPage::NotifyTenantsOfRename
  748.  *
  749.  * Purpose:
  750.  *  Loops through all the tenants and informs each of the new
  751.  *  document name.
  752.  *
  753.  * Parameters:
  754.  *  pszFile         LPTSTR of the new filename.
  755.  *  pmk             LPMONKIER for the new filename.
  756.  *
  757.  * Return Value:
  758.  *  None
  759.  */
  760. void CPage::NotifyTenantsOfRename(LPTSTR pszFile, LPMONIKER pmk)
  761.     {
  762.     PCTenant    pTenant;
  763.     UINT        i;
  764.     for (i=0; i < m_cTenants; i++)
  765.         {
  766.         if (TenantGet(i, &pTenant, FALSE))
  767.             pTenant->NotifyOfRename(pszFile, pmk);
  768.         }
  769.     return;
  770.     }
  771. /*
  772.  * CPage::ConvertObject
  773.  *
  774.  * Purpose:
  775.  *  Invokes and handles the results of the Convert dialog
  776.  *
  777.  * Parameters:
  778.  *  hWndFrame       HWND to use as the parent of the dialog.
  779.  *  fNoServer       BOOL indicating if this was called because
  780.  *                  ActivateObject failed.
  781.  *
  782.  * Return Value:
  783.  *  None
  784.  */
  785. BOOL CPage::ConvertObject(HWND hWndFrame, BOOL fNoServer)
  786.     {
  787.     HRESULT         hr;
  788.     OLEUICONVERT    ct;
  789.     TENANTTYPE      tType;
  790.     TENANTINFO      ti;
  791.     UINT            uRet;
  792.     HCURSOR         hCur;
  793.     BOOL            fActivate=fNoServer;
  794.     SIZEL           szl;
  795.     if (NULL==m_pTenantCur)
  796.         return FALSE;
  797.     tType=m_pTenantCur->TypeGet();
  798.     if (TENANTTYPE_STATIC==tType)
  799.         {
  800.         MessageBeep(0);
  801.         return FALSE;
  802.         }
  803.     //Get object information we may want.
  804.     m_pTenantCur->GetInfo(&ti);
  805.     //Fill the structure.
  806.     memset(&ct, 0, sizeof(ct));
  807.     ct.cbStruct=sizeof(OLEUICONVERT);
  808.     ct.hWndOwner=hWndFrame;
  809.     //CHAPTER20MOD
  810.     ct.fIsLinkedObject=(TENANTTYPE_LINKEDOBJECT==tType);
  811.     //End CHAPTER20MOD
  812.     ct.dvAspect=ti.fe.dwAspect;
  813.     m_pTenantCur->ObjectClassFormatAndIcon(&ct.clsid, &ct.wFormat
  814.         , &ct.lpszUserType, &ct.hMetaPict, &ct.lpszDefLabel);
  815.     uRet=OleUIConvert(&ct);
  816.     if (OLEUI_OK==uRet)
  817.         {
  818.         //Potentially a long operation.
  819.         hCur=SetCursor(LoadCursor(NULL, IDC_WAIT));
  820.         //Prevent multiple repaints.
  821.         m_pTenantCur->EnableRepaint(FALSE);
  822.         //First, let's bother with the iconic aspect switch.
  823.         if ((DVASPECT_ICON==ct.dvAspect && ct.fObjectsIconChanged)
  824.             || ct.dvAspect!=ti.fe.dwAspect)
  825.             {
  826.             HGLOBAL     hMem=NULL;
  827.             //Only pass non-NULL handle for icon aspects.
  828.             if (DVASPECT_ICON==ct.dvAspect)
  829.                 hMem=ct.hMetaPict;
  830.             m_pPG->m_fDirty=m_pTenantCur->SwitchOrUpdateAspect(hMem
  831.                 , FALSE);
  832.             }
  833.         //Now change types around.
  834.         if ((CF_SELECTCONVERTTO & ct.dwFlags)
  835.             && ct.clsid!=ct.clsidNew)
  836.             {
  837.             LPSTORAGE   pIStorage;
  838.             /*
  839.              * User selected convert, so:
  840.              *  1.  Unload the object (back to passive state)
  841.              *  2.  Call INOLE_DoConvert, which calls WriteClassStg,
  842.              *      WriteFmtUserTypeStg, and SetConvertStg.
  843.              *  3.  Reload the object and force an update.
  844.              */
  845.             //This should be the only close necessary.
  846.             m_pTenantCur->StorageGet(&pIStorage);
  847.             m_pTenantCur->Close(TRUE);
  848.             hr=INOLE_DoConvert(pIStorage, ct.clsidNew);
  849.             //Need to commit the new type and format
  850.             pIStorage->Commit(STGC_DEFAULT);
  851.             pIStorage->Release();
  852.             if (SUCCEEDED(hr))
  853.                 {
  854.                 LPUNKNOWN   pObj;
  855.                 LPOLEOBJECT pIOleObject;
  856.                 //Reload and update.
  857.                 m_pTenantCur->Load(m_pIStorage, &ti);
  858.                 m_pTenantCur->ObjectGet(&pObj);
  859.                 pObj->QueryInterface(IID_IOleObject
  860.                     , (PPVOID)&pIOleObject);
  861.                 pIOleObject->Update();
  862.                 pIOleObject->Release();
  863.                 pObj->Release();
  864.                 }
  865.             m_pPG->m_fDirty=TRUE;
  866.             }
  867.         if (CF_SELECTACTIVATEAS & ct.dwFlags)
  868.             {
  869.             /*
  870.              * User selected Activate As, so:
  871.              *  1.  Add the TreatAs entry in the registry
  872.              *      through CoTreatAsClass
  873.              *  2.  Unload all objects of the old CLSID that you
  874.              *      have loaded.
  875.              *  3.  Reload objects as desired
  876.              *  4.  Activate the current object.
  877.              */
  878.             hr=CoTreatAsClass(ct.clsid, ct.clsidNew);
  879.             if (SUCCEEDED(hr))
  880.                 {
  881.                 PCTenant    pTenant;
  882.                 UINT        i;
  883.                 for (i=0; i < m_cTenants; i++)
  884.                     {
  885.                     if (TenantGet(i, &pTenant, FALSE))
  886.                         {
  887.                         pTenant->GetInfo(&ti);
  888.                         pTenant->Close(FALSE);
  889.                         pTenant->Load(m_pIStorage, &ti);
  890.                         }
  891.                     }
  892.                 fActivate=TRUE;
  893.                 }
  894.             }
  895.         //These two steps insure the object knows of the size.
  896.         m_pTenantCur->SizeGet(&szl, FALSE);
  897.         m_pTenantCur->SizeSet(&szl, FALSE, TRUE);
  898.         m_pTenantCur->EnableRepaint(TRUE);
  899.         m_pTenantCur->Repaint();
  900.         if (fActivate)
  901.             m_pTenantCur->Activate(OLEIVERB_SHOW);
  902.         SetCursor(hCur);
  903.         }
  904.     CoTaskMemFree((void*)ct.lpszUserType);
  905.     INOLE_MetafilePictIconFree(ct.hMetaPict);
  906.     return TRUE;
  907.     }
  908. //CHAPTER17MOD
  909. /*
  910.  * CPage::FQueryLinksInPage
  911.  *
  912.  * Purpose:
  913.  *  Pass through to current page to see if there are any linked
  914.  *  objects.
  915.  *
  916.  * Parameters:
  917.  *  None
  918.  *
  919.  * Return Value:
  920.  *  None
  921.  */
  922. BOOL CPage::FQueryLinksInPage()
  923.     {
  924.     PCTenant    pTenant;
  925.     UINT        i;
  926.     BOOL        fRet=FALSE;
  927.     for (i=0; i < m_cTenants; i++)
  928.         {
  929.         if (TenantGet(i, &pTenant, FALSE))
  930.             fRet |= (pTenant->TypeGet()==TENANTTYPE_LINKEDOBJECT);
  931.         }
  932.     return fRet;
  933.     }
  934. //End CHAPTER20MOD
  935. /*
  936.  * CPage::TenantGet
  937.  * (Protected)
  938.  *
  939.  * Purpose:
  940.  *  Returns a tenant of a given index returning a BOOL so it's
  941.  *  simple to use this function inside if statements.
  942.  *
  943.  * Parameters:
  944.  *  iTenant         UINT tenant to retrieve 0 based.
  945.  *  ppTenant        PCPage * in which to return the tenant
  946.  *                  pointer
  947.  *  fOpen           BOOL indicating if we should open this
  948.  *                  tenant as well.
  949.  *
  950.  * Return Value:
  951.  *  BOOL            TRUE if successful, FALSE otherwise.
  952.  */
  953. BOOL CPage::TenantGet(UINT iTenant, PCTenant *ppTenant
  954.     , BOOL fOpen)
  955.     {
  956.     if (NULL==ppTenant)
  957.         return FALSE;
  958.     if (LB_ERR!=SendMessage(m_hWndTenantList, LB_GETTEXT
  959.         , iTenant, (LONG)ppTenant))
  960.         {
  961.         if (fOpen)
  962.             (*ppTenant)->Open(m_pIStorage);
  963.         return TRUE;
  964.         }
  965.     return FALSE;
  966.     }
  967. /*
  968.  * CPage::TenantAdd
  969.  * (Protected)
  970.  *
  971.  * Purpose:
  972.  *  Creates a new tenant initialized to the given values.  The new
  973.  *  tenants's storage is created if it does not already exist.  If
  974.  *  fOpenStorage is set the the tenants's storage is opened and left
  975.  *  opened.
  976.  *
  977.  * Parameters:
  978.  *  iTenant         UINT Location at which to insert tenant; new
  979.  *                  tenant is inserted after this position.  NOVALUE
  980.  *                  for the end.
  981.  *  dwID            DWORD ID for this tenant.
  982.  *  ppNew           PCTenant * in which to store the new tenant.
  983.  *
  984.  * Return Value:
  985.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  986.  */
  987. BOOL CPage::TenantAdd(UINT iTenant, DWORD dwID
  988.     , PCTenant *ppNew)
  989.     {
  990.     PCTenant    pTenant;
  991.     LRESULT     lr;
  992.     if (NULL!=ppNew)
  993.         *ppNew=NULL;
  994.     pTenant=new CTenant(dwID, m_hWnd, m_pPG);
  995.     if (NULL==pTenant)
  996.         return FALSE;
  997.     //The constructor doesn't AddRef, so we need to.
  998.     pTenant->AddRef();
  999.     //Now try to add to the listbox.
  1000.     lr=SendMessage(m_hWndTenantList, LB_INSERTSTRING, iTenant
  1001.         , (LONG)pTenant);
  1002.     if (lr < 0)
  1003.         {
  1004.         pTenant->Release();
  1005.         return FALSE;
  1006.         }
  1007.     *ppNew=pTenant;
  1008.     return TRUE;
  1009.     }
  1010. /*
  1011.  * CPage::TransferObjectCreate
  1012.  * (Protected)
  1013.  *
  1014.  * Purpose:
  1015.  *  Creates a DataTransferObject and stuff the current selection's
  1016.  *  data into it.
  1017.  *
  1018.  * Parameters:
  1019.  *  pptl            PPOINTL containing the pick point in device
  1020.  *                  units applicable only to drag-drop; since
  1021.  *                  drag-drop is inherently mouse oriented, we use
  1022.  *                  device units for the point.  Ignored if NULL.
  1023.  *
  1024.  * Return Value:
  1025.  *  LPDATAOBJECT    Pointer to the object created, NULL on failure
  1026.  */
  1027. LPDATAOBJECT CPage::TransferObjectCreate(PPOINTL pptl)
  1028.     {
  1029.     LPDATAOBJECT    pIDataObject;
  1030.     LPDATAOBJECT    pIDataT;
  1031.     PPATRONOBJECT   ppo;
  1032.     RECTL           rcl;
  1033.     LPUNKNOWN       pObj;
  1034.     FORMATETC       fe;
  1035.     STGMEDIUM       stm;
  1036.     HRESULT         hr;
  1037.     m_pTenantCur->ObjectGet(&pObj);
  1038.     hr=CoCreateInstance(CLSID_DataTransferObject, NULL
  1039.         , CLSCTX_INPROC_SERVER, IID_IDataObject
  1040.         , (PPVOID)&pIDataObject);
  1041.     if (FAILED(hr))
  1042.         return NULL;
  1043.     //Go get the data we should hold on to.
  1044.     hr=pObj->QueryInterface(IID_IDataObject, (PPVOID)&pIDataT);
  1045.     if (FAILED(hr))
  1046.         {
  1047.         pIDataObject->Release();
  1048.         pObj->Release();
  1049.         return NULL;
  1050.         }
  1051.     //Copy from known obj into transfer obj.  Ordering is important!
  1052.     //Generate placeable object structure
  1053.     stm.tymed=TYMED_HGLOBAL;
  1054.     stm.pUnkForRelease=NULL;
  1055.     stm.hGlobal=GlobalAlloc(GHND, sizeof(PATRONOBJECT));
  1056.     if (NULL==stm.hGlobal)
  1057.         {
  1058.         pIDataObject->Release();
  1059.         pObj->Release();
  1060.         return NULL;
  1061.         }
  1062.     ppo=(PPATRONOBJECT)GlobalLock(stm.hGlobal);
  1063.     m_pTenantCur->SizeGet(&ppo->szl, FALSE);
  1064.     ppo->szl.cy=-ppo->szl.cy; //Negate to make absolute size
  1065.     m_pTenantCur->RectGet(&rcl, FALSE);
  1066.     ppo->ptl.x=rcl.left;
  1067.     ppo->ptl.y=rcl.top;
  1068.     if (NULL==pptl)
  1069.         {
  1070.         ppo->ptlPick.x=0;
  1071.         ppo->ptlPick.y=0;
  1072.         }
  1073.     else
  1074.         ppo->ptlPick=*pptl;
  1075.     m_pTenantCur->FormatEtcGet(&ppo->fe, FALSE);
  1076.     //CHAPTER20MOD
  1077.     //If this is a linked object, just copy a presentation
  1078.     if (TENANTTYPE_LINKEDOBJECT==m_pTenantCur->TypeGet())
  1079.         m_pTenantCur->FormatEtcGet(&ppo->fe, TRUE);
  1080.     //End CHAPTER20MOD
  1081.     SETDefFormatEtc(fe, m_pPG->m_cf, TYMED_HGLOBAL);
  1082.     pIDataObject->SetData(&fe, &stm, TRUE);
  1083.     /*
  1084.      * Here now we have to include CFSTR_EMBEDDEDOBJECT and
  1085.      * CFSTR_OBJECTDESCRIPTOR when what we have selected is, in
  1086.      * fact, a compound document object.  We'll just ask the tenant
  1087.      * to set these in pIDataObject since it knows what the object.
  1088.      * If we copy embedded object data, make sure the PATRONOBJECT
  1089.      * structure has the right format in it as well.
  1090.      */
  1091.     m_pTenantCur->CopyEmbeddedObject(pIDataObject, &ppo->fe, pptl);
  1092.     GlobalUnlock(stm.hGlobal);
  1093.     //Copy the actual presentation.
  1094.     m_pTenantCur->FormatEtcGet(&fe, TRUE);
  1095.     pIDataT->GetData(&fe, &stm);
  1096.     pIDataObject->SetData(&fe, &stm, TRUE);
  1097.     pIDataT->Release();
  1098.     pObj->Release();
  1099.     return pIDataObject;    //Caller now responsible
  1100.     }