home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / tutsamp / perclien / guilist.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-05  |  55.2 KB  |  1,837 lines

  1. /*+==========================================================================
  2.   File:      GUILIST.CPP
  3.  
  4.   Summary:   Implementation file for the CGuiList C++ class. A GuiList is
  5.              a C++ object that displays a list of pages that are kept in a
  6.              compound file. The CGuiList provides the main application
  7.              window for the PERCLIEN application. During the operation of
  8.              this application CGuiList is used to manage a list of
  9.              editable pages. These pages have their own child windows. For
  10.              example, GUIDRAW.CPP codes the drawing page window and
  11.              GUITEXT.CPP codes the text page window. CGuiList is anchored
  12.              to the Windows GUI (Graphical User Interface) environment--it
  13.              retains knowledge of window handles and device contexts on
  14.              the local machine. This GuiList object relies on a virtual
  15.              List object for persistent storage of the list of pages.
  16.              This virtual List object (a COPageList) is instantiated
  17.              as a COM object in a separate In-process server, PERSERVE.
  18.  
  19.              For a comprehensive tutorial code tour of GUILIST's contents
  20.              and offerings see the tutorial PERCLIEN.HTM file. For more
  21.              specific technical details on the internal workings see the
  22.              comments dispersed throughout the GUILIST source code.
  23.  
  24.   Classes:   CGuiList.
  25.  
  26.   Origin:    5-20-97: atrent - Editor inheritance from GUIPAPER.CPP in the
  27.              STOCLIEN source.
  28.  
  29. ----------------------------------------------------------------------------
  30.   This file is part of the Microsoft COM Tutorial Code Samples.
  31.  
  32.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  33.  
  34.   This source code is intended only as a supplement to Microsoft
  35.   Development Tools and/or on-line documentation.  See these other
  36.   materials for detailed information regarding Microsoft code samples.
  37.  
  38.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  39.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  40.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  41.   PARTICULAR PURPOSE.
  42. ==========================================================================+*/
  43.  
  44. /*--------------------------------------------------------------------------
  45.   We include WINDOWS.H for all Win32 applications.
  46.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  47.   We include OLECTL.H because it has definitions for connectable objects.
  48.   We include COMMDLG.H because we will be using the Open File and
  49.     potentially other Common dialogs.
  50.   We include TCHAR.H for general Unicode/Ansi prototype of utility
  51.     functions like _tsplitpath, etc.
  52.   We include APPUTIL.H because we will be building this application using
  53.     the convenient Virtual Window and Dialog classes and other
  54.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  55.   We include IPAGES.H and PAGEGUID.H for the common page-related Interface
  56.     class, GUID, and CLSID specifications.
  57.   We include RESDEF.H because it has class and resource definitions
  58.     specific to this application.
  59.   We include PAGEFILE.H because it has the C++ class used for compound file
  60.     storage of page list ata.
  61.   We include LISTWIN.H because CGuiList creates and uses a CListWin to
  62.     manage a standard list box window.
  63.   We include GUILIST.H because it has the C++ class used for GUI display
  64.     of the page List.
  65.   We include LISTSINK.H because it has the C++ class used for the sink
  66.     that receives event notifications from COPageList in the server.
  67.   We include TEXTWIN.H because it has the C++ class that encapsulates
  68.     the standard multi-line text editing window/control.
  69.   We include GUITEXT.H because it has the C++ class used for GUI display
  70.     of text pages.
  71.   We include TEXTSINK.H because it has the C++ class used for the sink
  72.     that receives event notifications from COTextPage in the server.
  73.   We include GUIDRAW.H because it has the C++ class used for GUI display
  74.     of drawing pages.
  75.   We include DRAWSINK.H because it has the C++ class used for the sink
  76.     that receives event notifications from CODrawPage in the server.
  77.   We include PERCLIEN.H because it has the class declarations for the
  78.     main window of this application.
  79. ---------------------------------------------------------------------------*/
  80. #include <windows.h>
  81. #include <ole2.h>
  82. #include <olectl.h>
  83. #include <commdlg.h>
  84. #include <tchar.h>
  85. #include <apputil.h>
  86. #include <ipages.h>
  87. #include <pageguid.h>
  88. #include "resdef.h"
  89. #include "pagefile.h"
  90. #include "listwin.h"
  91. #include "guilist.h"
  92. #include "listsink.h"
  93. #include "textwin.h"
  94. #include "guitext.h"
  95. #include "textsink.h"
  96. #include "guidraw.h"
  97. #include "drawsink.h"
  98. #include "perclien.h"
  99.  
  100.  
  101. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  102.   Method:   CGuiList::CGuiList
  103.  
  104.   Summary:  Constructor.
  105.  
  106.   Args:     void
  107.  
  108.   Returns:  void
  109. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  110. CGuiList::CGuiList(void)
  111. {
  112.   m_hWnd            = NULL;
  113.   m_hInst           = NULL;
  114.   m_pIPageList      = NULL;
  115.   m_pIStorage_Root  = NULL;
  116.   m_pCOPageListSink = NULL;
  117.   m_dwPageListSink  = 0;
  118.   m_pListWin        = NULL;
  119.   m_pPageFile       = NULL;
  120.   m_bChanged        = FALSE;
  121.  
  122.   // Init the file name for title display to <MyModule>.<EXT>.
  123.   if (GetModuleFileName(m_hInst, m_szFileName, MAX_PATH))
  124.   {
  125.     _tsplitpath(m_szFileName, NULL, NULL, m_szFileTitle, NULL);
  126.     lstrcat(m_szFileTitle, TEXT(PAG_FILE_EXT));
  127.   }
  128.  
  129.   // Ensure the m_szFileName OFN member variable string is NULL.
  130.   m_szFileName[0] = 0;
  131.  
  132.   // Zero the open list array.
  133.   memset(m_paOpenList, 0, OPENLIST_SIZE * sizeof(OPENITEM));
  134. }
  135.  
  136.  
  137. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  138.   Method:   CGuiList::~CGuiList
  139.  
  140.   Summary:  Destructor.
  141.  
  142.   Args:     void
  143.  
  144.   Returns:  void
  145. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  146. CGuiList::~CGuiList(void)
  147. {
  148.   if (m_pIPageList)
  149.   {
  150.     // Use CGuiList's Close method to close down the PageList. This
  151.     // disconnects the Sink, performs final release of the COPageList
  152.     // object, and closes the file by releasing the IStorage for the file.
  153.     Close();
  154.  
  155.     // Release the reference to the PageListSink object.
  156.     RELEASE_INTERFACE(m_pCOPageListSink);
  157.  
  158.     // Delete the CPageFile object.
  159.     DELETE_POINTER(m_pPageFile);
  160.  
  161.     // Delete the CListWin object.
  162.     DELETE_POINTER(m_pListWin);
  163.   }
  164. }
  165.  
  166.  
  167. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  168.   Method:   CGuiList::Init
  169.  
  170.   Summary:  Get CGuiList started. Make any subordinate objects, like
  171.             COPageList, CListWin, and CPageFile, and get them started.
  172.  
  173.   Args:     HINSTANCE hInst
  174.               Handle to the application instance.
  175.             HWND hWnd
  176.               Handle of the display window. Part of what makes CGuiList
  177.               a GUI kind of thing.
  178.             TCHAR* pszCmdLineFile)
  179.               Pointer to file name for an initial file to load that was
  180.               specified on the app command line.
  181.  
  182.   Returns:  BOOL
  183.               TRUE for success; FALSE for fail.
  184. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  185. BOOL CGuiList::Init(
  186.        HINSTANCE hInst,
  187.        HWND hWnd,
  188.        TCHAR* pszCmdLineFile)
  189. {
  190.   BOOL bOk = FALSE;
  191.   HRESULT hr;
  192.   COPageListSink* pCob = NULL;
  193.   HCURSOR hCurPrev;
  194.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  195.  
  196.   if (hInst && hWnd)
  197.   {
  198.     m_hInst = hInst;
  199.     m_hWnd = hWnd;
  200.  
  201.     // Change cursor to the hour glass. Init could take awhile.
  202.     hCurPrev = SetCursor(hCurWait);
  203.  
  204.     // Fill in the Open File Name Common Dialog's OPENFILENAME structure.
  205.     m_ofnFile.lStructSize = sizeof(OPENFILENAME);
  206.     m_ofnFile.hwndOwner = hWnd;
  207.     m_ofnFile.hInstance = hInst;
  208.     m_ofnFile.lpstrCustomFilter = NULL;
  209.     m_ofnFile.nMaxCustFilter = 0;
  210.     m_ofnFile.nFilterIndex = 1;
  211.     m_ofnFile.lpstrFile = m_szFileName;
  212.     m_ofnFile.nMaxFile = MAX_PATH;
  213.     m_ofnFile.lpstrInitialDir = TEXT(".");
  214.     m_ofnFile.lpstrFileTitle = m_szFileTitle;
  215.     m_ofnFile.nMaxFileTitle = MAX_PATH;
  216.     m_ofnFile.lpstrDefExt = TEXT(PAG_EXT);
  217.  
  218.     if (LoadString(m_hInst, IDS_OFN_PAGFILES, m_szFileFilter, MAX_PATH))
  219.       m_ofnFile.lpstrFilter = m_szFileFilter;
  220.     else
  221.       m_ofnFile.lpstrFilter = TEXT(OFN_DEFAULTFILES_STR);
  222.  
  223.     // Create the CPageFile object so we can store page list data in
  224.     // .PAG compound files.
  225.     m_pPageFile = new CPageFile;
  226.     if (NULL != m_pPageFile)
  227.     {
  228.       if (FileExist(pszCmdLineFile))
  229.       {
  230.         // If the user specified a file name on the app's command
  231.         // invocation line then use that name if it actually refers
  232.         // to an existing file. If not then ignore it.
  233.         lstrcpy(m_szFileName, pszCmdLineFile);
  234.         lstrcpy(m_szFileTitle, pszCmdLineFile);
  235.       }
  236.       else
  237.       {
  238.         // Build a path to where the default application .PAG file
  239.         // should be. It should be in the same directory as the .EXE
  240.         // as the appname with an .PAG extension.
  241.         MakeFamilyPath(m_hInst, m_szFileName, TEXT(PAG_FILE_EXT));
  242.       }
  243.  
  244.       // Init the CPageFile object.
  245.       hr = m_pPageFile->Init(m_szFileName);
  246.       if (SUCCEEDED(hr))
  247.       {
  248.         // Create the CListWin object so we can show page list data
  249.         // in a list box window.
  250.         m_pListWin = new CListWin;
  251.         if (NULL != m_pListWin)
  252.         {
  253.           if (m_pListWin->Create(m_hInst, m_hWnd, FALSE))
  254.           {
  255.             // Create the COPageListSink object to receive PageList events.
  256.             pCob = new COPageListSink(NULL, this);
  257.             if (NULL != pCob)
  258.             {
  259.               // Save a pointer to the COPageListSink IUnknown interface.
  260.               // AddRef because of this saved copy. Released in destructor.
  261.               m_pCOPageListSink = pCob;
  262.               m_pCOPageListSink->AddRef();
  263.               bOk = TRUE;
  264.             }
  265.           }
  266.         }
  267.       }
  268.     }
  269.  
  270.     // Set Cursor from hourglass back to what it was.
  271.     SetCursor(hCurPrev);
  272.   }
  273.  
  274.   return (bOk);
  275. }
  276.  
  277.  
  278. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  279.   Method:   CGuiList::GetConnectionPoint
  280.  
  281.   Summary:  Internal private method to obtain a connection point interface.
  282.  
  283.   Args:     REFIID riid
  284.               IID of the requested connection point Interface.
  285.  
  286.   Returns:  IConnectionPoint*
  287.               Requested IConnectionPoint interface pointer. NULL if none.
  288. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  289. IConnectionPoint* CGuiList::GetConnectionPoint(
  290.                     REFIID riid)
  291. {
  292.   IConnectionPoint* pConnPoint = NULL;
  293.   IConnectionPointContainer* pConnPointContainer = NULL;
  294.   IConnectionPoint* pConnPt;
  295.   HRESULT hr;
  296.  
  297.   // First query the object for its Connection Point Container. This
  298.   // essentially asks the object in the server if it is connectable.
  299.   hr = m_pIPageList->QueryInterface(
  300.          IID_IConnectionPointContainer,
  301.          (PPVOID)&pConnPointContainer);
  302.   if SUCCEEDED(hr)
  303.   {
  304.     // Find the requested Connection Point. This AddRef's the
  305.     // returned pointer.
  306.     hr = pConnPointContainer->FindConnectionPoint(riid, &pConnPt);
  307.     if (SUCCEEDED(hr))
  308.       pConnPoint = pConnPt;
  309.  
  310.     RELEASE_INTERFACE(pConnPointContainer);
  311.   }
  312.  
  313.   return pConnPoint;
  314. }
  315.  
  316.  
  317. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  318.   Method:   CGuiList::ConnectSink
  319.  
  320.   Summary:  Connect the PageListSink to the server COPageList event
  321.             source.
  322.  
  323.   Args:     void
  324.  
  325.   Returns:  HRESULT
  326.               Standard result code. NOERROR for success.
  327. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  328. HRESULT CGuiList::ConnectSink(void)
  329. {
  330.   HRESULT hr = E_FAIL;
  331.   DWORD dwKey;
  332.   IConnectionPoint* pConnPoint;
  333.  
  334.   if (!m_dwPageListSink)
  335.   {
  336.     // Get the PageList Sink connection point in the server.
  337.     pConnPoint = GetConnectionPoint(IID_IPageListSink);
  338.     if (NULL != pConnPoint)
  339.     {
  340.       // Connect the server's object to the PageList Sink in this client.
  341.       hr = pConnPoint->Advise(m_pCOPageListSink, &dwKey);
  342.       if (SUCCEEDED(hr))
  343.         m_dwPageListSink = dwKey;
  344.  
  345.       RELEASE_INTERFACE(pConnPoint);
  346.     }
  347.   }
  348.  
  349.   return hr;
  350. }
  351.  
  352.  
  353. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  354.   Method:   CGuiList::DisconnectSink
  355.  
  356.   Summary:  Disconnect the PageListSink from the server COPageList event
  357.             source.
  358.  
  359.   Args:     void.
  360.  
  361.   Returns:  HRESULT
  362.               Standard result code. NOERROR for success.
  363. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  364. HRESULT CGuiList::DisconnectSink(void)
  365. {
  366.   HRESULT hr = E_FAIL;
  367.   IConnectionPoint* pConnPoint;
  368.  
  369.   if (m_dwPageListSink)
  370.   {
  371.     // Get the PageList Sink connection point.
  372.     pConnPoint = GetConnectionPoint(IID_IPageListSink);
  373.     if (NULL != pConnPoint)
  374.     {
  375.       // Disconnect the object in the server from the PageList Sink in
  376.       // this client.
  377.       hr = pConnPoint->Unadvise(m_dwPageListSink);
  378.       if (SUCCEEDED(hr))
  379.         m_dwPageListSink = 0;
  380.  
  381.       RELEASE_INTERFACE(pConnPoint);
  382.     }
  383.   }
  384.  
  385.   return hr;
  386. }
  387.  
  388.  
  389. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  390.   Method:   CGuiList::Resize
  391.  
  392.   Summary:  Handle a user-initiated Resize of the app's main window.
  393.             Pass this resize on to the child list box window.
  394.  
  395.   Args:     WORD wWidth,
  396.               New width of window in pixels.
  397.             WORD wHeight)
  398.               New height of window in pixels.
  399.  
  400.   Returns:  HRESULT
  401.               Standard result code. NOERROR for success.
  402. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  403. HRESULT CGuiList::Resize(
  404.           WORD wWidth,
  405.           WORD wHeight)
  406. {
  407.   HRESULT hr = E_FAIL;
  408.   BOOL bOk = FALSE;
  409.  
  410.   bOk = m_pListWin->Resize(wWidth, wHeight);
  411.   if (bOk)
  412.     hr = NOERROR;
  413.  
  414.   return hr;
  415. }
  416.  
  417.  
  418. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  419.   Method:   CGuiList::Show
  420.  
  421.   Summary:  Show the content of the page list by putting the list content
  422.             into a standard list box control/window.
  423.  
  424.   Args:     INT iNewSel)
  425.               The highlighted current selection index in the list.
  426.               If < 0 then use/restore the current list box selection.
  427.               If >= 0 then set the selection to the index specified.
  428.  
  429.   Returns:  HRESULT
  430.               Standard result code. NOERROR for success.
  431. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  432. HRESULT CGuiList::Show(
  433.           INT iNewSel)
  434. {
  435.   HRESULT hr = E_FAIL;
  436.   INT iPage = 0;
  437.   INT iCurSel;
  438.   BOOL bDone = FALSE;
  439.   BOOL bOpen = FALSE;
  440.   SHORT nType = PAGETYPE_NONE;
  441.   WCHAR wszTitle[PAGE_TITLE_SIZE];
  442.   WCHAR wszDataName[PAGE_NAME_SIZE];
  443.   TCHAR szOpen[4];
  444.   TCHAR szType[4];
  445.  
  446.   // Get currently selected page index.
  447.   if (iNewSel < 0)
  448.     m_pListWin->GetCurSel(&iCurSel);
  449.   else
  450.     iCurSel = iNewSel;
  451.  
  452.   // First clear all ListWin display content.
  453.   m_pListWin->Clear();
  454.  
  455.   // Now loop. Ask COPageList for all Page List items and add
  456.   // display entries for them in ListWin.
  457.   while (!bDone)
  458.   {
  459.     hr = m_pIPageList->Get(iPage, &bOpen, &nType, wszTitle, wszDataName);
  460.     if (SUCCEEDED(hr))
  461.     {
  462.       if (bOpen)
  463.         lstrcpy(szOpen, TEXT(PAGE_OPEN_STR));
  464.       else
  465.         lstrcpy(szOpen, TEXT(PAGE_CLOSED_STR));
  466.  
  467.       switch (nType)
  468.       {
  469.         case PAGETYPE_TEXT:
  470.           lstrcpy(szType, TEXT(TYPE_TEXT_STR));
  471.           break;
  472.         case PAGETYPE_DRAWING:
  473.           lstrcpy(szType, TEXT(TYPE_DRAWING_STR));
  474.           break;
  475.         default:
  476.           lstrcpy(szType, TEXT(TYPE_UNKNOWN_STR));
  477.           break;
  478.       }
  479. #if defined(UNICODE)
  480.       hr = m_pListWin->AddFmt(
  481.                          TEXT(LISTWIN_FMT_STR),
  482.                          szOpen,
  483.                          iPage,
  484.                          szType,
  485.                          wszTitle);
  486. #else
  487.       {
  488.         CHAR szTitle[PAGE_TITLE_SIZE];
  489.  
  490.         UcToAnsi(wszTitle, szTitle, 0);
  491.         hr = m_pListWin->AddFmt(
  492.                            TEXT(LISTWIN_FMT_STR),
  493.                            szOpen,
  494.                            iPage,
  495.                            szType,
  496.                            szTitle);
  497.       }
  498. #endif
  499.       iPage++;
  500.     }
  501.     else
  502.     {
  503.       hr = NOERROR;
  504.       bDone = TRUE;
  505.     }
  506.   }
  507.  
  508.   // Restore currently selected page index.
  509.   m_pListWin->SetCurSel(iCurSel);
  510.  
  511.   return hr;
  512. }
  513.  
  514.  
  515. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  516.   Method:   CGuiList::GetOpenItem
  517.  
  518.   Summary:  Private method. Get the open item for a specified page. Also
  519.             indicate whether the open array can accept any new open items.
  520.  
  521.   Args:     INT iPage,
  522.               The requested page number of the page to get. Can be -1
  523.               indicating that only the AddOk status is requested.
  524.             SHORT* pnPageType,
  525.               Address of the output page type variable for the requested
  526.               open page item. Can be NULL indicating no request.
  527.             PPVOID ppGuiPage,
  528.               Address of the output pointer variable that receives a
  529.               pointer to the C++ object that controls the page's window.
  530.               Can be NULL indicating no request.
  531.             BOOL* pAddOk)
  532.               Address of the output BOOL variable that, if TRUE, signals
  533.               the caller whether any new items can be added/opened.
  534.  
  535.   Returns:  HRESULT
  536.               Standard result code. NOERROR for success.
  537. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  538. HRESULT CGuiList::GetOpenItem(
  539.           INT iPage,
  540.           SHORT* pnPageType,
  541.           PPVOID ppGuiPage,
  542.           BOOL* pAddOk)
  543. {
  544.   HRESULT hr = E_FAIL;
  545.   SHORT nOpenType;
  546.   INT i;
  547.   BOOL bAddOk = FALSE;
  548.  
  549.   // Loop thru the open list array and find the open page.
  550.   for (i=0; i<OPENLIST_SIZE; i++)
  551.   {
  552.     nOpenType = m_paOpenList[i].nType;
  553.  
  554.     if (!bAddOk && pAddOk != NULL && nOpenType == PAGETYPE_NONE)
  555.       *pAddOk = bAddOk = TRUE;
  556.  
  557.     if (nOpenType != PAGETYPE_NONE && m_paOpenList[i].iPage == iPage)
  558.     {
  559.       if (E_FAIL == hr)
  560.       {
  561.         if (NULL != pnPageType)
  562.           *pnPageType = m_paOpenList[i].nType;
  563.         if (NULL != ppGuiPage)
  564.           *ppGuiPage = m_paOpenList[i].pGuiPage;
  565.         hr = NOERROR;
  566.       }
  567.     }
  568.   }
  569.  
  570.   return hr;
  571. }
  572.  
  573.  
  574. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  575.   Method:   CGuiList::AddOpenItem
  576.  
  577.   Summary:  Private method. Add a new open item to the open item array.
  578.  
  579.   Args:     INT iPage,
  580.               Page number of new open item.
  581.             SHORT nPageType,
  582.               Page type of new open item.
  583.             void* pGuiPage)
  584.               Pointer to window control C++ object (eg, pGuiText).
  585.  
  586.   Returns:  HRESULT
  587.               Standard result code. NOERROR for success.
  588. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  589. HRESULT CGuiList::AddOpenItem(
  590.           INT iPage,
  591.           SHORT nPageType,
  592.           void* pGuiPage)
  593. {
  594.   HRESULT hr = E_FAIL;
  595.   SHORT nOpenType;
  596.   INT i;
  597.  
  598.   // Loop thru the open list array and find an empty slot.
  599.   for (i=0; i<OPENLIST_SIZE; i++)
  600.   {
  601.     nOpenType = m_paOpenList[i].nType;
  602.  
  603.     if (nOpenType == PAGETYPE_NONE)
  604.     {
  605.       m_paOpenList[i].nType = nPageType;
  606.       m_paOpenList[i].iPage = iPage;
  607.       m_paOpenList[i].pGuiPage = pGuiPage;
  608.       hr = NOERROR;
  609.       break;
  610.     }
  611.   }
  612.  
  613.   return hr;
  614. }
  615.  
  616.  
  617. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  618.   Method:   CGuiList::DeleteOpenItem
  619.  
  620.   Summary:  Private method. Delete the specified open item from the
  621.             open item array.
  622.  
  623.   Args:     INT iPage,
  624.               Dynamic number of page to delete.
  625.  
  626.   Returns:  HRESULT
  627.               Standard result code. NOERROR for success.
  628. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  629. HRESULT CGuiList::DeleteOpenItem(
  630.           INT iPage)
  631. {
  632.   HRESULT hr = E_FAIL;
  633.   SHORT nOpenType;
  634.   INT i;
  635.  
  636.   // Loop thru the open list array and find the open page.
  637.   for (i=0; i<OPENLIST_SIZE; i++)
  638.   {
  639.     nOpenType = m_paOpenList[i].nType;
  640.  
  641.     if (nOpenType != PAGETYPE_NONE && m_paOpenList[i].iPage == iPage)
  642.     {
  643.       // When found, mark the item as PAGETYPE_DELETED.
  644.       m_paOpenList[i].nType = PAGETYPE_DELETED;
  645.       hr = NOERROR;
  646.       break;
  647.     }
  648.   }
  649.  
  650.   return hr;
  651. }
  652.  
  653.  
  654. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  655.   Method:   CGuiList::RenumOpenItems
  656.  
  657.   Summary:  Private method. Renumber appropriate items in the open item
  658.             array to account for a permanently deleted page.
  659.  
  660.   Args:     INT iPage,
  661.               Dynamic number of deleted page.
  662.  
  663.   Returns:  HRESULT
  664.               Standard result code. NOERROR for success.
  665. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  666. HRESULT CGuiList::RenumOpenItems(
  667.           INT iPage)
  668. {
  669.   HRESULT hr = NOERROR;
  670.   SHORT nOpenType = PAGETYPE_NONE;
  671.   INT i, iPg;
  672.   CGuiText* pGuiText;
  673.   CGuiDraw* pGuiDraw;
  674.  
  675.   // Renumber the remaining open pages to account for a permanently
  676.   // deleted page.
  677.   for (i=0; i<OPENLIST_SIZE; i++)
  678.   {
  679.     nOpenType = m_paOpenList[i].nType;
  680.     iPg = m_paOpenList[i].iPage;
  681.  
  682.     if (nOpenType != PAGETYPE_NONE && iPg >= 0 && iPg > iPage)
  683.     {
  684.       if (iPg > 0)
  685.       {
  686.         iPg--;
  687.         m_paOpenList[i].iPage = iPg;
  688.         // Tell the open pages that they have a new dynamic page number.
  689.         switch (nOpenType)
  690.         {
  691.           case PAGETYPE_TEXT:
  692.             pGuiText = (CGuiText*) m_paOpenList[i].pGuiPage;
  693.             if (NULL != pGuiText)
  694.               hr = pGuiText->Renumber(iPg);
  695.             break;
  696.           case PAGETYPE_DRAWING:
  697.             pGuiDraw = (CGuiDraw*) m_paOpenList[i].pGuiPage;
  698.             if (NULL != pGuiDraw)
  699.               hr = pGuiDraw->Renumber(iPg);
  700.             break;
  701.           default:
  702.             break;
  703.         }
  704.       }
  705.     }
  706.   }
  707.  
  708.   return hr;
  709. }
  710.  
  711.  
  712. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  713.   Method:   CGuiList::CloseOpenItem
  714.  
  715.   Summary:  Private method. Delete the open item for the specified page
  716.             in the open item array.
  717.  
  718.   Args:     INT iPage,
  719.               Dynamic number of page open item to delete.
  720.  
  721.   Returns:  HRESULT
  722.               Standard result code. NOERROR for success.
  723. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  724. HRESULT CGuiList::CloseOpenItem(
  725.           INT iPage)
  726. {
  727.   HRESULT hr = E_FAIL;
  728.   SHORT nOpenType = PAGETYPE_NONE;
  729.   INT i;
  730.  
  731.   // Loop thru the open list array and find the open page entry.
  732.   for (i=0; i<OPENLIST_SIZE; i++)
  733.   {
  734.     nOpenType = m_paOpenList[i].nType;
  735.  
  736.     if (nOpenType != PAGETYPE_NONE && m_paOpenList[i].iPage == iPage)
  737.     {
  738.       // When found, mark the item as PAGETYPE_NONE.
  739.       m_paOpenList[i].nType = PAGETYPE_NONE;
  740.       hr = NOERROR;
  741.       break;
  742.     }
  743.   }
  744.  
  745.   // Renumber the remaining open pages to account for a permanently
  746.   // deleted page.
  747.   if (SUCCEEDED(hr) && PAGETYPE_DELETED == nOpenType)
  748.     RenumOpenItems(iPage);
  749.  
  750.   return hr;
  751. }
  752.  
  753.  
  754. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  755.   Method:   CGuiList::SaveOpenPages
  756.  
  757.   Summary:  Private method. Loop through the open list and save all
  758.             open pages.
  759.  
  760.   Args:     void.
  761.  
  762.   Returns:  HRESULT
  763.               Standard result code. NOERROR for success.
  764. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  765. HRESULT CGuiList::SaveOpenPages(void)
  766. {
  767.   HRESULT hr = E_FAIL;
  768.   SHORT nOpenType;
  769.   CGuiText* pGuiText;
  770.   CGuiDraw* pGuiDraw;
  771.   INT i;
  772.  
  773.   // Loop thru the open list array and save all open pages.
  774.   for (i=0; i<OPENLIST_SIZE; i++)
  775.   {
  776.     nOpenType = m_paOpenList[i].nType;
  777.  
  778.     switch (nOpenType)
  779.     {
  780.       case PAGETYPE_TEXT:
  781.         pGuiText = (CGuiText*) m_paOpenList[i].pGuiPage;
  782.         if (NULL != pGuiText)
  783.           hr = pGuiText->Save();
  784.         break;
  785.       case PAGETYPE_DRAWING:
  786.         pGuiDraw = (CGuiDraw*) m_paOpenList[i].pGuiPage;
  787.         if (NULL != pGuiDraw)
  788.           hr = pGuiDraw->Save();
  789.         break;
  790.       default:
  791.         break;
  792.     }
  793.   }
  794.  
  795.   if (SUCCEEDED(hr))
  796.   {
  797.     // All open pages saved so clear any changed flag.
  798.     m_bChanged = FALSE;
  799.   }
  800.  
  801.   return hr;
  802. }
  803.  
  804.  
  805. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  806.   Method:   CGuiList::CloseOpenPages
  807.  
  808.   Summary:  Private method. Loop through the open list and close all
  809.             open pages.
  810.  
  811.   Args:     void.
  812.  
  813.   Returns:  HRESULT
  814.               Standard result code. NOERROR for success.
  815. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  816. HRESULT CGuiList::CloseOpenPages(void)
  817. {
  818.   HRESULT hr = E_FAIL;
  819.   SHORT nOpenType;
  820.   INT i;
  821.   CGuiText* pGuiText;
  822.   CGuiDraw* pGuiDraw;
  823.  
  824.   // Loop thru the open list array and close all open pages.
  825.   for (i=0; i<OPENLIST_SIZE; i++)
  826.   {
  827.     nOpenType = m_paOpenList[i].nType;
  828.  
  829.     switch (nOpenType)
  830.     {
  831.       case PAGETYPE_TEXT:
  832.         pGuiText = (CGuiText*) m_paOpenList[i].pGuiPage;
  833.         if (NULL != pGuiText)
  834.         {
  835.           hr = pGuiText->Close();
  836.           if (SUCCEEDED(hr))
  837.           {
  838.             m_paOpenList[i].nType = PAGETYPE_NONE;
  839.           }
  840.         }
  841.         break;
  842.       case PAGETYPE_DRAWING:
  843.         pGuiDraw = (CGuiDraw*) m_paOpenList[i].pGuiPage;
  844.         if (NULL != pGuiDraw)
  845.         {
  846.           hr = pGuiDraw->Close();
  847.           if (SUCCEEDED(hr))
  848.           {
  849.             m_paOpenList[i].nType = PAGETYPE_NONE;
  850.           }
  851.         }
  852.         break;
  853.       default:
  854.         break;
  855.     }
  856.   }
  857.  
  858.   if (SUCCEEDED(hr))
  859.   {
  860.     m_bChanged = FALSE;
  861.   }
  862.  
  863.   return hr;
  864. }
  865.  
  866.  
  867. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  868.   Method:   CGuiList::ReleaseOpenPages
  869.  
  870.   Summary:  Private method. Loop throught the open list array and
  871.             release storage for all open pages.
  872.  
  873.   Args:     void.
  874.  
  875.   Returns:  HRESULT
  876.               Standard result code. NOERROR for success.
  877. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  878. HRESULT CGuiList::ReleaseOpenPages(void)
  879. {
  880.   HRESULT hr = E_FAIL;
  881.   SHORT nOpenType;
  882.   INT i;
  883.   CGuiText* pGuiText;
  884.   CGuiDraw* pGuiDraw;
  885.  
  886.   // Loop thru the open list array and release all open page storage.
  887.   for (i=0; i<OPENLIST_SIZE; i++)
  888.   {
  889.     nOpenType = m_paOpenList[i].nType;
  890.  
  891.     switch (nOpenType)
  892.     {
  893.       case PAGETYPE_TEXT:
  894.         pGuiText = (CGuiText*) m_paOpenList[i].pGuiPage;
  895.           hr = pGuiText->ReleasePage();
  896.         break;
  897.       case PAGETYPE_DRAWING:
  898.         pGuiDraw = (CGuiDraw*) m_paOpenList[i].pGuiPage;
  899.         if (NULL != pGuiDraw)
  900.           hr = pGuiDraw->ReleasePage();
  901.         break;
  902.       default:
  903.         break;
  904.     }
  905.   }
  906.  
  907.   return hr;
  908. }
  909.  
  910.  
  911. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  912.   Method:   CGuiList::RestoreOpenPages
  913.  
  914.   Summary:  Private method. Loop through the open list array and reopen
  915.             storage for the open pages. Use the specified root storage.
  916.  
  917.   Args:     IStorage* pIStorage_Root)
  918.               Root storage for the compound file containing the pages.
  919.  
  920.   Returns:  HRESULT
  921.               Standard result code. NOERROR for success.
  922. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  923. HRESULT CGuiList::RestoreOpenPages(
  924.           IStorage* pIStorage_Root)
  925. {
  926.   HRESULT hr = E_FAIL;
  927.   SHORT nOpenType;
  928.   INT i;
  929.   CGuiText* pGuiText;
  930.   CGuiDraw* pGuiDraw;
  931.  
  932.   // Loop thru the open list array and reopen storage for the open pages.
  933.   for (i=0; i<OPENLIST_SIZE; i++)
  934.   {
  935.     nOpenType = m_paOpenList[i].nType;
  936.  
  937.     switch (nOpenType)
  938.     {
  939.       case PAGETYPE_TEXT:
  940.         pGuiText = (CGuiText*) m_paOpenList[i].pGuiPage;
  941.         if (NULL != pGuiText)
  942.         {
  943.           hr = pGuiText->RestorePage(pIStorage_Root);
  944.           if (SUCCEEDED(hr))
  945.           {
  946.             // Make sure the Text page in the reopend storage
  947.             // matches the Text page object data in RAM.
  948.             hr = pGuiText->Save();
  949.           }
  950.         }
  951.         break;
  952.       case PAGETYPE_DRAWING:
  953.         pGuiDraw = (CGuiDraw*) m_paOpenList[i].pGuiPage;
  954.         if (NULL != pGuiDraw)
  955.         {
  956.           hr = pGuiDraw->RestorePage(pIStorage_Root);
  957.           if (SUCCEEDED(hr))
  958.           {
  959.             // Make sure the Draw page in the reopend storage
  960.             // matches the Draw page object data in RAM.
  961.             hr = pGuiDraw->Save();
  962.           }
  963.         }
  964.         break;
  965.       default:
  966.         break;
  967.     }
  968.   }
  969.  
  970.   return hr;
  971. }
  972.  
  973.  
  974. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  975.   Method:   CGuiList::Load
  976.  
  977.   Summary:  Load PageList data from the current compound file.
  978.  
  979.   Args:     void.
  980.  
  981.   Returns:  HRESULT
  982.               Standard result code. NOERROR for success.
  983. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  984. HRESULT CGuiList::Load(void)
  985. {
  986.   HRESULT hr = E_FAIL;
  987.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  988.   HCURSOR hCurPrev;
  989.   TCHAR szTitle[MAX_PATH + 32];
  990.  
  991.   if (NULL != m_pPageFile)
  992.   {
  993.     // Change cursor to the hour glass.
  994.     hCurPrev = SetCursor(hCurWait);
  995.  
  996.     // Ask the PageFile object to load the PageList data from the current
  997.     // compound file. This load internally uses IPersist* features in a
  998.     // COPageList object that is created and reconstituted from
  999.     // persistent storage.
  1000.     hr = m_pPageFile->Load(NULL, &m_pIStorage_Root, &m_pIPageList);
  1001.     if (SUCCEEDED(hr))
  1002.     {
  1003.       // If we created and reconstituted a COPageList object then
  1004.       // connect the sinks in the client to the connection sources
  1005.       // in the server.
  1006.       hr = ConnectSink();
  1007.       if (SUCCEEDED(hr))
  1008.       {
  1009.         // Set Main Window Title.
  1010.         lstrcpy(szTitle, TEXT(MAIN_APP_NAME_STR));
  1011.         lstrcat(szTitle, m_szFileTitle);
  1012.         SetWindowText(m_hWnd, szTitle);
  1013.  
  1014.         // Set focus to ListWin and select first item in list.
  1015.         m_pListWin->SetCurSel(0);
  1016.  
  1017.         // Newly loaded file isn't changed yet.
  1018.         m_bChanged = FALSE;
  1019.       }
  1020.     }
  1021.  
  1022.     // Set Cursor back to what it was.
  1023.     SetCursor(hCurPrev);
  1024.   }
  1025.  
  1026.   return hr;
  1027. }
  1028.  
  1029.  
  1030. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1031.   Method:   CGuiList::Save
  1032.  
  1033.   Summary:  Calls on CPageFile to save the current PageList data in
  1034.             the current compound file.
  1035.  
  1036.   Args:     void.
  1037.  
  1038.   Returns:  HRESULT
  1039.               Standard result code. NOERROR for success.
  1040. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1041. HRESULT CGuiList::Save(void)
  1042. {
  1043.   HRESULT hr = E_FAIL;
  1044.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1045.   HCURSOR hCurPrev;
  1046.  
  1047.   if (NULL != m_pPageFile)
  1048.   {
  1049.     // Change cursor to the hour glass.
  1050.     hCurPrev = SetCursor(hCurWait);
  1051.  
  1052.     // Save any open pages if needed.
  1053.     SaveOpenPages();
  1054.  
  1055.     // Ask the PageFile object to save itself to the current file.
  1056.     hr = m_pPageFile->Save(m_pIStorage_Root, m_pIPageList);
  1057.     if (SUCCEEDED(hr))
  1058.       m_bChanged = FALSE;
  1059.  
  1060.     // Set Cursor back to what it was.
  1061.     SetCursor(hCurPrev);
  1062.   }
  1063.  
  1064.   return hr;
  1065. }
  1066.  
  1067.  
  1068. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1069.   Method:   CGuiList::AskSave
  1070.  
  1071.   Summary:  Checks if any open pages were changed or if the PageList dirty
  1072.             flag is set. The dirty flag is TRUE if the current PageList
  1073.             data was modified and is out of sync with the PageList data
  1074.             stored in the compound file. If a page was changed or if the
  1075.             PageList is dirty, then ask user in a simple dialog if he
  1076.             wants to save everthing. If he says yes, then save the current
  1077.             PageList data into the current compound file and tell any
  1078.             changed open pages to do the same.
  1079.  
  1080.   Args:     void.
  1081.  
  1082.   Returns:  HRESULT
  1083.               Standard result code. NOERROR for success.
  1084. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1085. int CGuiList::AskSave(void)
  1086. {
  1087.   int iAns = IDNO;
  1088.   HRESULT hr;
  1089.   TCHAR szTitle[MAX_STRING_LENGTH];
  1090.   TCHAR szAsk[MAX_STRING_LENGTH];
  1091.   TCHAR szMsg[MAX_PATH + MAX_STRING_LENGTH];
  1092.   IPersistStream* pIPersistStream;
  1093.  
  1094.   hr = m_pIPageList->QueryInterface(
  1095.            IID_IPersistStream,
  1096.            (PPVOID)&pIPersistStream);
  1097.   if (SUCCEEDED(hr))
  1098.   {
  1099.     // Did any page change or is the PageList object dirty?
  1100.     if (m_bChanged || S_FALSE != pIPersistStream->IsDirty())
  1101.     {
  1102.       // The current data is dirty; ask user if he wants to save it.
  1103.       if (LoadString(m_hInst, IDS_FILE_CHANGED, szTitle, MAX_STRING_LENGTH)
  1104.         && LoadString(m_hInst, IDS_ASK_SAVE, szAsk, MAX_STRING_LENGTH))
  1105.       {
  1106.         lstrcpy(szMsg, m_szFileName);
  1107.         lstrcat(szMsg, szAsk);
  1108.         // Display AskSaveDlg to user. Ask if he wants to save.
  1109.         iAns = MessageBox(
  1110.                  m_hWnd,
  1111.                  szMsg,
  1112.                  szTitle,
  1113.                  MB_YESNOCANCEL | MB_ICONEXCLAMATION);
  1114.         switch (iAns)
  1115.         {
  1116.           case IDYES:
  1117.             // Tell CPageFile to save itself to the current compound file.
  1118.             // Save any changed open pages as well.
  1119.             Save();
  1120.             break;
  1121.           case IDNO:
  1122.             // User clicked No. So don't save; abandon changes.
  1123.             m_bChanged = FALSE;
  1124.             break;
  1125.           case IDCANCEL:
  1126.           default:
  1127.             break;
  1128.         }
  1129.       }
  1130.     }
  1131.  
  1132.     // Done with IPersistStream for now so release it.
  1133.     pIPersistStream->Release();
  1134.   }
  1135.  
  1136.   return iAns;
  1137. }
  1138.  
  1139.  
  1140. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1141.   Method:   CGuiList::Close
  1142.  
  1143.   Summary:  Close down the existing Page List. This saves the current file
  1144.             if needed, disconnects the sinks, releases the COPageList COM
  1145.             object, and closes the file by releasing the IStorage.
  1146.  
  1147.   Args:     void.
  1148.  
  1149.   Returns:  HRESULT
  1150.               Standard result code. NOERROR for success.
  1151. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1152. HRESULT CGuiList::Close(void)
  1153. {
  1154.   HRESULT hr = NOERROR;
  1155.   TCHAR szTitle[MAX_PATH];
  1156.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1157.   HCURSOR hCurPrev;
  1158.  
  1159.   // Change cursor to the hour glass.
  1160.   hCurPrev = SetCursor(hCurWait);
  1161.  
  1162.   // Save the page list into the existing .PAG file if needed.
  1163.   m_pPageFile->Save(m_pIStorage_Root, m_pIPageList);
  1164.  
  1165.   // Disconnect the Sink in the client from the connection points in
  1166.   // the server.
  1167.   DisconnectSink();
  1168.  
  1169.   // Close the file by releasing the root IStorage.
  1170.   RELEASE_INTERFACE(m_pIStorage_Root);
  1171.  
  1172.   // Destroy the existing COPageList by releasing the IPageList interface.
  1173.   RELEASE_INTERFACE(m_pIPageList);
  1174.  
  1175.   // Set Main Window Title.
  1176.   lstrcpy(szTitle, TEXT(MAIN_APP_NAME_STR));
  1177.   lstrcat(szTitle, TEXT(NOFILE_STR));
  1178.   SetWindowText(m_hWnd, szTitle);
  1179.  
  1180.   // Set Cursor back to what it was.
  1181.   SetCursor(hCurPrev);
  1182.  
  1183.   return hr;
  1184. }
  1185.  
  1186.  
  1187. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1188.   Method:   CGuiList::Open
  1189.  
  1190.   Summary:  If current PageList data has been modified then ask user if he
  1191.             wants to first save it to the current file. Then use Open File
  1192.             Name common dialog to ask user for a new file name to load. If
  1193.             user chooses a file name then load the PageList data from that
  1194.             compound file.
  1195.  
  1196.   Args:     void.
  1197.  
  1198.   Returns:  HRESULT
  1199.               Standard result code. NOERROR for success.
  1200. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1201. HRESULT CGuiList::Open(void)
  1202. {
  1203.   HRESULT hr = NOERROR;
  1204.   TCHAR szFileName[MAX_PATH];
  1205.   TCHAR szTitle[MAX_PATH];
  1206.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1207.   HCURSOR hCurPrev;
  1208.   BOOL bOpen;
  1209.  
  1210.   // If current data is dirty then ask user if he wants to save it first.
  1211.   if (IDCANCEL != AskSave())
  1212.   {
  1213.     // Use the Open File Name common dialog to get file name from user.
  1214.     // Set the dialog's file filter and title.
  1215.     szFileName[0] = 0;
  1216.     m_ofnFile.lpstrFile = szFileName;
  1217.     if (LoadString(m_hInst, IDS_OFN_PAGOPEN, szTitle, sizeof(szTitle)))
  1218.       m_ofnFile.lpstrTitle = szTitle;
  1219.     m_ofnFile.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  1220.  
  1221.     // Call up the dialog to get a file name from the user.
  1222.     bOpen = GetOpenFileName(&m_ofnFile);
  1223.     if (bOpen)
  1224.     {
  1225.       // Change cursor to the hour glass.
  1226.       hCurPrev = SetCursor(hCurWait);
  1227.  
  1228.       // Close any open pages.
  1229.       CloseOpenPages();
  1230.  
  1231.       // Close down the existing Page List. This saves the current
  1232.       // file if needed, disconnects the sinks, releases the
  1233.       // COPageList COM object, and closes the file by releasing
  1234.       // the root IStorage.
  1235.       Close();
  1236.  
  1237.       // Tell CPageFile object to load the Page List data from the newly
  1238.       // chosen compound file. This creates a new COPageList object.
  1239.       hr = m_pPageFile->Load(szFileName, &m_pIStorage_Root, &m_pIPageList);
  1240.       if (SUCCEEDED(hr))
  1241.       {
  1242.         // Connect the sinks in the client to the connection sources
  1243.         // in the server.
  1244.         hr = ConnectSink();
  1245.         if (SUCCEEDED(hr))
  1246.         {
  1247.           // Remember the new current compound file name.
  1248.           lstrcpy(m_szFileName, szFileName);
  1249.  
  1250.           // Set Main Window Title.
  1251.           lstrcpy(szFileName, TEXT(MAIN_APP_NAME_STR));
  1252.           lstrcat(szFileName, m_szFileTitle);
  1253.           SetWindowText(m_hWnd, szFileName);
  1254.  
  1255.           // Set focus to ListWin and select first item in list and
  1256.           // show the newly loaded page list.
  1257.           Show(0);
  1258.         }
  1259.       }
  1260.  
  1261.       // Set Cursor back to what it was.
  1262.       SetCursor(hCurPrev);
  1263.     }
  1264.   }
  1265.  
  1266.   return hr;
  1267. }
  1268.  
  1269.  
  1270. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1271.   Method:   CGuiList::SaveAs
  1272.  
  1273.   Summary:  Use the File SaveAs common dialog to ask user for a new file
  1274.             name to save to. Then save the current PageList data to the
  1275.             specified compound file. That file becomes the new current
  1276.             file. The previously open file is closed and left unchanged
  1277.             since the last save to it.
  1278.  
  1279.   Args:     void.
  1280.  
  1281.   Returns:  HRESULT
  1282.               Standard result code. NOERROR for success.
  1283. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1284. HRESULT CGuiList::SaveAs(void)
  1285. {
  1286.   HRESULT hr = E_FAIL;
  1287.   TCHAR szFileName[MAX_PATH];
  1288.   TCHAR szTitle[MAX_PATH];
  1289.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1290.   HCURSOR hCurPrev;
  1291.   BOOL bOpen;
  1292.  
  1293.   // Use the File Save As common dialog to get file name from user.
  1294.   // Set the dialog's file filter and title.
  1295.   szFileName[0] = 0;
  1296.   m_ofnFile.lpstrFile = szFileName;
  1297.   if (LoadString(m_hInst, IDS_OFN_PAGSAVE, szTitle, sizeof(szTitle)))
  1298.     m_ofnFile.lpstrTitle = szTitle;
  1299.   m_ofnFile.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
  1300.  
  1301.   // Call up the dialog to get a file name from the user.
  1302.   bOpen = GetSaveFileName(&m_ofnFile);
  1303.   if (bOpen)
  1304.   {
  1305.     // Change cursor to the hour glass.
  1306.     hCurPrev = SetCursor(hCurWait);
  1307.  
  1308.     // No need to close any open page windows. But we do need to
  1309.     // release the existing Storage interfaces that are held for
  1310.     // those pages. For Drawing pages supporting IPersistStorage this
  1311.     // eventually calls HandsOffStorage on all the open draw pages.
  1312.     hr = ReleaseOpenPages();
  1313.  
  1314.     // Do the final close of the root storage of the existing file.
  1315.     RELEASE_INTERFACE(m_pIStorage_Root);
  1316.  
  1317.     // All open storages/streams in the file are released and closed.
  1318.     // Now copy a clone of the existing file (for the SaveAs).
  1319.     if (CopyFile(m_szFileName, szFileName, FALSE))
  1320.     {
  1321.       // Tell CPageFile object to save the PageList data to the newly
  1322.       // copied compound file.
  1323.       hr = m_pPageFile->SaveAs(szFileName, m_pIPageList, &m_pIStorage_Root);
  1324.       if (SUCCEEDED(hr))
  1325.       {
  1326.         // Client is done changing the file from underneath the open
  1327.         // pages. Now re-open storage for the existing open pages
  1328.         // using the data storages in the new file. For Drawing pages
  1329.         // that support IPersistStorage this eventually calls
  1330.         // SaveCompleted on all the open draw pages.
  1331.         hr = RestoreOpenPages(m_pIStorage_Root);
  1332.         if (SUCCEEDED(hr))
  1333.         {
  1334.           // Remember the new current compound file name.
  1335.           lstrcpy(m_szFileName, szFileName);
  1336.  
  1337.           // Set Main Window Title.
  1338.           lstrcpy(szFileName, TEXT(MAIN_APP_NAME_STR));
  1339.           lstrcat(szFileName, m_szFileTitle);
  1340.           SetWindowText(m_hWnd, szFileName);
  1341.  
  1342.           // Restored pages are assumed to match their file image.
  1343.           m_bChanged = FALSE;
  1344.         }
  1345.       }
  1346.     }
  1347.  
  1348.     // Set Cursor back to what it was.
  1349.     SetCursor(hCurPrev);
  1350.   }
  1351.  
  1352.   return hr;
  1353. }
  1354.  
  1355.  
  1356. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1357.   Method:   CGuiList::New
  1358.  
  1359.   Summary:  If current PageList data has been modified then ask user if he
  1360.             wants to first save it to the current file. Then use the
  1361.             SaveAs File Name common dialog to ask user for a new file name
  1362.             to Create. If user chooses a file name then create an empty
  1363.             new PageList compound file using the file name specified.
  1364.  
  1365.   Args:     void.
  1366.  
  1367.   Returns:  HRESULT
  1368.               Standard result code. NOERROR for success.
  1369. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1370. HRESULT CGuiList::New(void)
  1371. {
  1372.   HRESULT hr = NOERROR;
  1373.   TCHAR szFileName[MAX_PATH];
  1374.   TCHAR szTitle[MAX_PATH];
  1375.   HCURSOR hCurWait = LoadCursor(NULL, IDC_WAIT);
  1376.   HCURSOR hCurPrev;
  1377.   BOOL bOpen;
  1378.  
  1379.   // If current data is dirty then ask user if he wants to save it first.
  1380.   if (IDCANCEL != AskSave())
  1381.   {
  1382.     // Use the File Save As common dialog to get file name from user.
  1383.     // Set the dialog's file filter and title.
  1384.     szFileName[0] = 0;
  1385.     m_ofnFile.lpstrFile = szFileName;
  1386.     if (LoadString(m_hInst, IDS_OFN_PAGSAVE, szTitle, sizeof(szTitle)))
  1387.       m_ofnFile.lpstrTitle = szTitle;
  1388.     m_ofnFile.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
  1389.  
  1390.     // Call up the dialog to get a file name from the user.
  1391.     bOpen = GetSaveFileName(&m_ofnFile);
  1392.     if (bOpen)
  1393.     {
  1394.       // Change cursor to the hour glass.
  1395.       hCurPrev = SetCursor(hCurWait);
  1396.  
  1397.       // Close any open pages.
  1398.       CloseOpenPages();
  1399.  
  1400.       // Close down the existing Page List. This saves the current
  1401.       // file if needed, disconnects the sinks, releases the COPageList
  1402.       // COM object, and closes the file by releasing the IStorage.
  1403.       Close();
  1404.  
  1405.       // Tell CPageFile object to create a new empty .PAG compound
  1406.       // file using the specified file name. This also creates
  1407.       // a new COPageList object.
  1408.       hr = m_pPageFile->New(szFileName, &m_pIStorage_Root, &m_pIPageList);
  1409.       if (SUCCEEDED(hr))
  1410.       {
  1411.         // Connect the sinks in the client to the connection sources
  1412.         // in the server.
  1413.         hr = ConnectSink();
  1414.         if (SUCCEEDED(hr))
  1415.         {
  1416.           // Remember the new current compound file name.
  1417.           lstrcpy(m_szFileName, szFileName);
  1418.  
  1419.           // Set Main Window Title.
  1420.           lstrcpy(szFileName, TEXT(MAIN_APP_NAME_STR));
  1421.           lstrcat(szFileName, m_szFileTitle);
  1422.           SetWindowText(m_hWnd, szFileName);
  1423.  
  1424.           // Set focus to ListWin and select first item in list and
  1425.           // show the newly loaded page list.
  1426.           Show(0);
  1427.         }
  1428.       }
  1429.  
  1430.       // Set Cursor back to what it was.
  1431.       SetCursor(hCurPrev);
  1432.     }
  1433.   }
  1434.  
  1435.   return hr;
  1436. }
  1437.  
  1438.  
  1439. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1440.   Method:   CGuiList::PageTitle
  1441.  
  1442.   Summary:  Uses a dialog box to edit the title of the currently selected
  1443.             page list item.
  1444.  
  1445.   Args:     void.
  1446.  
  1447.   Returns:  HRESULT
  1448.               Standard result code. NOERROR for success.
  1449. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1450. HRESULT CGuiList::PageTitle(void)
  1451. {
  1452.   HRESULT hr = E_FAIL;
  1453.   BOOL bOk;
  1454.   INT iOk, iPage;
  1455.   CDlgPageProps dlgPageProps;
  1456.   WCHAR wszPageTitle[PAGE_TITLE_SIZE];
  1457.  
  1458.   bOk = m_pListWin->GetCurSel(&iPage);
  1459.   if (bOk)
  1460.   {
  1461.     // Get the Page List title for this page number.
  1462. #if defined(UNICODE)
  1463.     hr = m_pIPageList->Get(iPage, NULL, NULL, g_szPageTitle, NULL);
  1464. #else
  1465.     hr = m_pIPageList->Get(iPage, NULL, NULL, wszPageTitle, NULL);
  1466.     if (SUCCEEDED(hr))
  1467.       UcToAnsi(wszPageTitle, g_szPageTitle, PAGE_TITLE_SIZE);
  1468. #endif
  1469.  
  1470.     // Ask the user for the new title of the page in the Page
  1471.     // Properties dialog.
  1472.     iOk = dlgPageProps.ShowDialog(
  1473.             m_hInst,
  1474.             MAKEINTRESOURCE(IDD_PAGE_PROPS),
  1475.             m_hWnd);
  1476.     if (iOk)
  1477.     {
  1478.       // If the user clicked Ok, then a new title was edited.
  1479.       // Ask the COPageList object to set the new title.
  1480.       // Use the Title entered by the user.
  1481. #ifdef UNICODE
  1482.       hr = m_pIPageList->Set(iPage, 0, g_szPageTitle);
  1483. #else
  1484.       // Convert to Unicode if we are compiled for Ansi.
  1485.       AnsiToUc(g_szPageTitle, wszPageTitle, PAGE_TITLE_SIZE);
  1486.       hr = m_pIPageList->Set(iPage, 0, wszPageTitle);
  1487. #endif
  1488.     }
  1489.   }
  1490.  
  1491.   return hr;
  1492. }
  1493.  
  1494.  
  1495. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1496.   Method:   CGuiList::PageOpen
  1497.  
  1498.   Summary:  Opens and loads the page object associated with the currently
  1499.             selected page list item. A separate window is used for
  1500.             editing the data of the loaded page.
  1501.  
  1502.   Args:     void.
  1503.  
  1504.   Returns:  HRESULT
  1505.               Standard result code. NOERROR for success.
  1506. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1507. HRESULT CGuiList::PageOpen(void)
  1508. {
  1509.   HRESULT hr = E_FAIL;
  1510.   BOOL bOk;
  1511.   INT iPage;
  1512.   SHORT nType;
  1513.   WCHAR wszTitle[PAGE_TITLE_SIZE];
  1514.   WCHAR wszDataName[PAGE_NAME_SIZE];
  1515.   void* pGuiPage;
  1516.   CGuiText* pGuiText;
  1517.   CGuiDraw* pGuiDraw;
  1518.  
  1519.   bOk = m_pListWin->GetCurSel(&iPage);
  1520.   if (bOk)
  1521.   {
  1522.     hr = GetOpenItem(iPage, &nType, &pGuiPage, &bOk);
  1523.     if (FAILED(hr))
  1524.     {
  1525.       // Failed means this page is not already open for editing.
  1526.       if (bOk)
  1527.       {
  1528.         // bOk means there is room for another open page, Get the page's
  1529.         // DataName and Title from the COPageList COM object and then
  1530.         // Create the separate edit window.
  1531.         hr = m_pIPageList->Get(iPage, NULL, &nType, wszTitle, wszDataName);
  1532.         if (SUCCEEDED(hr))
  1533.         {
  1534.           switch (nType)
  1535.           {
  1536.             case PAGETYPE_TEXT:
  1537.               pGuiText = new CGuiText(m_hInst, m_hWnd, iPage);
  1538.               if (NULL != pGuiText)
  1539.               {
  1540.                 hr = pGuiText->OpenWin(m_pIStorage_Root, wszTitle, wszDataName);
  1541.                 if (SUCCEEDED(hr))
  1542.                 {
  1543.                   // Add an entry to the open list for the newly opened page.
  1544.                   hr = AddOpenItem(iPage, nType, pGuiText);
  1545.                 }
  1546.               }
  1547.               else
  1548.                 hr = E_OUTOFMEMORY;
  1549.               break;
  1550.             case PAGETYPE_DRAWING:
  1551.               pGuiDraw = new CGuiDraw(m_hInst, m_hWnd, iPage);
  1552.               if (NULL != pGuiDraw)
  1553.               {
  1554.                 hr = pGuiDraw->OpenWin(m_pIStorage_Root, wszTitle, wszDataName);
  1555.                 if (SUCCEEDED(hr))
  1556.                 {
  1557.                   // Add an entry to the open list for the newly opened page.
  1558.                   hr = AddOpenItem(iPage, nType, pGuiDraw);
  1559.                 }
  1560.               }
  1561.               else
  1562.                 hr = E_OUTOFMEMORY;
  1563.               break;
  1564.             default:
  1565.               break;
  1566.           }
  1567.         }
  1568.       }
  1569.       else
  1570.       {
  1571.         // Put up error message box saying that ther are too many
  1572.         // open pages.
  1573.         ErrorBox(m_hInst, m_hWnd, IDS_TOOMANYOPEN);
  1574.       }
  1575.     }
  1576.     else
  1577.     {
  1578.       // The page is already open. Bring its window to top.
  1579.       switch (nType)
  1580.       {
  1581.         case PAGETYPE_TEXT:
  1582.           pGuiText = (CGuiText*) pGuiPage;
  1583.           if (NULL != pGuiText)
  1584.             hr = pGuiText->TopWin();
  1585.           break;
  1586.         case PAGETYPE_DRAWING:
  1587.           pGuiDraw = (CGuiDraw*) pGuiPage;
  1588.           if (NULL != pGuiDraw)
  1589.             hr = pGuiDraw->TopWin();
  1590.           break;
  1591.         default:
  1592.           break;
  1593.       }
  1594.     }
  1595.   }
  1596.  
  1597.   return hr;
  1598. }
  1599.  
  1600.  
  1601. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1602.   Method:   CGuiList::PageAdd
  1603.  
  1604.   Summary:  Add a new page of specified type to the page list. First
  1605.             creates the new page using the appropriate server and then
  1606.             adds an appropriate entry in the page list.
  1607.  
  1608.   Args:     SHORT nPageType
  1609.               The page type (eg, PAGETYPE_DRAWING).
  1610.  
  1611.   Returns:  HRESULT
  1612.               Standard result code. NOERROR for success.
  1613. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1614. HRESULT CGuiList::PageAdd(
  1615.           SHORT nPageType)
  1616. {
  1617.   HRESULT hr = E_FAIL;
  1618.   BOOL bOk;
  1619.   WCHAR wszTitle[PAGE_TITLE_SIZE];
  1620.   WCHAR wszDataName[PAGE_NAME_SIZE];
  1621.   INT iPg;
  1622.   CGuiText* pGuiText;
  1623.   CGuiDraw* pGuiDraw;
  1624.  
  1625.   GetOpenItem(-1, NULL, NULL, &bOk);
  1626.   if (bOk)
  1627.   {
  1628.     // If there is room for another open page.
  1629.     // Ask the COPageList object to add a new page of the specified type.
  1630.     // Use "Untitled" as the default title.
  1631. #ifdef UNICODE
  1632.     hr = m_pIPageList->Add(-1, nPageType, TEXT(PAGE_UNTITLED_STR), &iPg);
  1633. #else
  1634.     {
  1635.       WCHAR wszPageTitle[PAGE_TITLE_SIZE];
  1636.  
  1637.       // Convert to Unicode if we are compiled for Ansi.
  1638.       AnsiToUc(TEXT(PAGE_UNTITLED_STR), wszPageTitle, PAGE_TITLE_SIZE);
  1639.       hr = m_pIPageList->Add(-1, nPageType, wszPageTitle, &iPg);
  1640.     }
  1641. #endif
  1642.  
  1643.     if (SUCCEEDED(hr))
  1644.     {
  1645.       // Open the new page for editing. Get the page's DataName and Title
  1646.       // and then Create the separate edit window.
  1647.       hr = m_pIPageList->Get(iPg, NULL, NULL, wszTitle, wszDataName);
  1648.       switch (nPageType)
  1649.       {
  1650.         case PAGETYPE_TEXT:
  1651.           pGuiText = new CGuiText(m_hInst, m_hWnd, iPg);
  1652.           if (NULL != pGuiText)
  1653.           {
  1654.             hr = pGuiText->OpenWin(m_pIStorage_Root, wszTitle, wszDataName);
  1655.             if (SUCCEEDED(hr))
  1656.             {
  1657.               // Add the newly opened page to the open list.
  1658.               hr = AddOpenItem(iPg, nPageType, pGuiText);
  1659.             }
  1660.           }
  1661.           else
  1662.             hr = E_OUTOFMEMORY;
  1663.           break;
  1664.         case PAGETYPE_DRAWING:
  1665.           pGuiDraw = new CGuiDraw(m_hInst, m_hWnd, iPg);
  1666.           if (NULL != pGuiDraw)
  1667.           {
  1668.             hr = pGuiDraw->OpenWin(m_pIStorage_Root, wszTitle, wszDataName);
  1669.             if (SUCCEEDED(hr))
  1670.             {
  1671.               // Add the newly opened page to the open list.
  1672.               hr = AddOpenItem(iPg, nPageType, pGuiDraw);
  1673.             }
  1674.           }
  1675.           else
  1676.             hr = E_OUTOFMEMORY;
  1677.           break;
  1678.         default:
  1679.           break;
  1680.       }
  1681.     }
  1682.   }
  1683.   else
  1684.   {
  1685.     // Put up error message box saying that ther are too many
  1686.     // open pages.
  1687.     ErrorBox(m_hInst, m_hWnd, IDS_TOOMANYOPEN);
  1688.   }
  1689.  
  1690.   return hr;
  1691. }
  1692.  
  1693.  
  1694. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1695.   Method:   CGuiList::PageDelete
  1696.  
  1697.   Summary:  Delete the page that corresponds to the currently selected
  1698.             page list item.
  1699.  
  1700.   Args:     void.
  1701.  
  1702.   Returns:  HRESULT
  1703.               Standard result code. NOERROR for success.
  1704. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1705. HRESULT CGuiList::PageDelete(void)
  1706. {
  1707.   HRESULT hr = E_FAIL;
  1708.   BOOL bOk;
  1709.   INT iPage;
  1710.   SHORT nType;
  1711.   WCHAR wszDataName[PAGE_NAME_SIZE];
  1712.   CGuiText* pGuiText = NULL;
  1713.   CGuiDraw* pGuiDraw = NULL;
  1714.  
  1715.   bOk = m_pListWin->GetCurSel(&iPage);
  1716.   if (bOk)
  1717.   {
  1718.     // Get the page's Type.
  1719.     hr = m_pIPageList->Get(iPage, NULL, &nType, NULL, wszDataName);
  1720.     if (SUCCEEDED(hr))
  1721.     {
  1722.       switch (nType)
  1723.       {
  1724.         case PAGETYPE_TEXT:
  1725.           hr = GetOpenItem(iPage, NULL, (void**)&pGuiText, NULL);
  1726.           if (SUCCEEDED(hr))
  1727.           {
  1728.             hr = pGuiText->Delete();
  1729.             if (SUCCEEDED(hr))
  1730.             {
  1731.               // Mark the open item as deleted. This will force a later
  1732.               // renumber of open page numbers to account for the
  1733.               // permanently missing page. This renumber will occur in
  1734.               // the PageClosed method when the page is closed.
  1735.               hr = DeleteOpenItem(iPage);
  1736.               // Now Close the GuiText window.
  1737.               pGuiText->Close();
  1738.             }
  1739.           }
  1740.           else
  1741.           {
  1742.             // If not open, just destroy the entire text page's stream.
  1743.             hr = m_pIStorage_Root->DestroyElement(wszDataName);
  1744.             if (SUCCEEDED(hr))
  1745.             {
  1746.               // Renumber any open pages as needed.
  1747.               hr = RenumOpenItems(iPage);
  1748.             }
  1749.           }
  1750.           break;
  1751.         case PAGETYPE_DRAWING:
  1752.           hr = GetOpenItem(iPage, NULL, (void**)&pGuiDraw, NULL);
  1753.           if (SUCCEEDED(hr))
  1754.           {
  1755.             hr = pGuiDraw->Delete();
  1756.             if (SUCCEEDED(hr))
  1757.             {
  1758.               // Mark the open item as deleted. This will force a later
  1759.               // renumber of open page numbers to account for the
  1760.               // permanently missing page. This renumber will occur in
  1761.               // the PageClosed method when the page is closed.
  1762.               hr = DeleteOpenItem(iPage);
  1763.               // Now Close the GuiDraw window.
  1764.               pGuiDraw->Close();
  1765.             }
  1766.           }
  1767.           else
  1768.           {
  1769.             // If not open, just destroy the entire draw page's storage.
  1770.             hr = m_pIStorage_Root->DestroyElement(wszDataName);
  1771.             if (SUCCEEDED(hr))
  1772.             {
  1773.               // Renumber any open pages as needed.
  1774.               hr = RenumOpenItems(iPage);
  1775.             }
  1776.           }
  1777.           break;
  1778.         default:
  1779.           break;
  1780.       }
  1781.     }
  1782.  
  1783.     if (SUCCEEDED(hr))
  1784.     {
  1785.       // Finally, delete the page from the page list.
  1786.       hr = m_pIPageList->Delete(iPage);
  1787.     }
  1788.   }
  1789.  
  1790.   return hr;
  1791. }
  1792.  
  1793.  
  1794. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1795.   Method:   CGuiList::PageChanged
  1796.  
  1797.   Summary:  An open page was changed.
  1798.  
  1799.   Args:     INT iPage)
  1800.               Page number of the page that changed.
  1801.  
  1802.   Returns:  HRESULT
  1803.               Standard result code. NOERROR for success.
  1804. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1805. HRESULT CGuiList::PageChanged(
  1806.          INT iPage)
  1807. {
  1808.   HRESULT hr = NOERROR;;
  1809.  
  1810.   m_bChanged |= TRUE;
  1811.  
  1812.   return hr;
  1813. }
  1814.  
  1815.  
  1816. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  1817.   Method:   CGuiList::PageClosed
  1818.  
  1819.   Summary:  A page editing window was closed.
  1820.  
  1821.   Args:     INT iPage)
  1822.               Page number of the page that was closed.
  1823.  
  1824.   Returns:  HRESULT
  1825.               Standard result code. NOERROR for success.
  1826. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  1827. HRESULT CGuiList::PageClosed(
  1828.          INT iPage)
  1829. {
  1830.   HRESULT hr;
  1831.  
  1832.   // Mark the open item for the page as closed in the open item array.
  1833.   hr = CloseOpenItem(iPage);
  1834.  
  1835.   return hr;
  1836. }
  1837.