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 / pagefile.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-05  |  20.2 KB  |  587 lines

  1. /*+==========================================================================
  2.   File:      PAGEFILE.CPP
  3.  
  4.   Summary:   Implementation file for the CPageFile C++ class. A CPageFile
  5.              is a C++ object that encapsulates load and save operations on
  6.              an COM structured storage compound file. CPageFile knows
  7.              about an underlying server-based persistent COM object,
  8.              COPageList, that manages the actual page list data.
  9.              COPageList supports persistence of its page list data by
  10.              exposing the IPersistStream interface.
  11.  
  12.              For a comprehensive tutorial code tour of PageFile's contents
  13.              and offerings see the tutorial PERCLIEN.HTM file. For more
  14.              specific technical details on the internal workings see the
  15.              comments dispersed throughout the PAGEFILE source code.
  16.  
  17.   Classes:   CPageFile.
  18.  
  19.   Functions: .
  20.  
  21.   Origin:    5-24-97: atrent - Created for PERCLIEN Code Sample.
  22.  
  23. ----------------------------------------------------------------------------
  24.   This file is part of the Microsoft COM Tutorial Code Samples.
  25.  
  26.   Copyright (C) Microsoft Corporation, 1997.  All rights reserved.
  27.  
  28.   This source code is intended only as a supplement to Microsoft
  29.   Development Tools and/or on-line documentation.  See these other
  30.   materials for detailed information regarding Microsoft code samples.
  31.  
  32.   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  33.   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  34.   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  35.   PARTICULAR PURPOSE.
  36. ==========================================================================+*/
  37.  
  38. /*--------------------------------------------------------------------------
  39.   We include WINDOWS.H for all Win32 applications.
  40.   We include OLE2.H because we will be calling the COM/OLE Libraries.
  41.   We include APPUTIL.H because we will be building this application using
  42.     the convenient Virtual Window and Dialog classes and other
  43.     utility functions in the APPUTIL Library (ie, APPUTIL.LIB).
  44.   We include IPAGES.H and PAGEGUID.H for the common page-related Interface
  45.     class, GUID, and CLSID specifications.
  46.   We include PAGEFILE.H because it has the C++ class declaration used
  47.     for CPageFile.
  48. ---------------------------------------------------------------------------*/
  49. #include <windows.h>
  50. #include <ole2.h>
  51. #include <apputil.h>
  52. #include <ipages.h>
  53. #include <pageguid.h>
  54. #include "pagefile.h"
  55.  
  56.  
  57. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  58.   Method:   CPageFile::CPageFile
  59.  
  60.   Summary:  CPageFile Constructor.
  61.  
  62.   Args:     void.
  63.  
  64.   Returns:  .
  65. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  66. CPageFile::CPageFile(void)
  67. {
  68.   m_szCurFileName[0] = 0;
  69.  
  70.   // Save the ClassID of PageLists using overloaded '=' operator.
  71.   m_CidPageList = CLSID_PageList;
  72. }
  73.  
  74.  
  75. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  76.   Method:   CPageFile::~CPageFile
  77.  
  78.   Summary:  CPageFile Destructor.
  79.  
  80.   Args:     void
  81.  
  82.   Returns:  .
  83. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  84. CPageFile::~CPageFile(void)
  85. {
  86. }
  87.  
  88.  
  89. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  90.   Method:   CPageFile::Init
  91.  
  92.   Summary:  Initializes the CPageFile C++ object.
  93.  
  94.   Args:     TCHAR* pszAppFileName
  95.               Name/Path of the app's default compound file to open.
  96.  
  97.   Returns:  HRESULT
  98.               Standard result code. NOERROR for success.
  99. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  100. HRESULT CPageFile::Init(
  101.           TCHAR* pszAppFileName)
  102. {
  103.   HRESULT hr = E_POINTER;
  104.  
  105.   if (NULL != pszAppFileName)
  106.   {
  107.     // Set the default current file name.
  108.     lstrcpy(m_szCurFileName, pszAppFileName);
  109.  
  110.     hr = NOERROR;
  111.   }
  112.  
  113.   return (hr);
  114. }
  115.  
  116.  
  117. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  118.   Method:   CPageFile::New
  119.  
  120.   Summary:  Create a new empty PageList compound file using the specified
  121.             file name.
  122.  
  123.   Args:     TCHAR* pszFileName,
  124.               Name/Path of the compound file to Create. If NULL then use
  125.               CPageFile's m_szCurFileName as the compound file to Create.
  126.             IStorage** ppIStorage,
  127.               Address of an IStorage pointer variable that will receive
  128.               the IStorage interface for the new PageList file.
  129.             IPageList** ppIPageList)
  130.               Address of an IPageList pointer variable that will receive
  131.               the IPageList interface for a new COPageList COM object.
  132.  
  133.   Returns:  HRESULT
  134.               Standard result code. NOERROR for success.
  135. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  136. HRESULT CPageFile::New(
  137.           TCHAR* pszFileName,
  138.           IStorage** ppIStorage,
  139.           IPageList** ppIPageList)
  140. {
  141.   HRESULT hr = E_POINTER;
  142.   BOOL bNewFile = (NULL != pszFileName);
  143.   TCHAR* pszFile;
  144.   IStorage* pIStorage;
  145.   IStream* pIStream;
  146.   IPersistStream* pIPersistStream;
  147.   IPageList* pIPageList;
  148.   ULARGE_INTEGER uliMaxSize;
  149.  
  150.   if (NULL != ppIStorage && NULL != ppIPageList)
  151.   {
  152.     // Zero the output pointers in case of errror.
  153.     *ppIStorage = NULL;
  154.     *ppIPageList = NULL;
  155.  
  156.     // If NULL file name passed then use current file name.
  157.     pszFile = bNewFile ? pszFileName : m_szCurFileName;
  158.  
  159.     // Use COM service to create a new compound file.
  160.     hr = StgCreateDocfile(
  161.            pszFile,
  162.            STGM_CREATE | STGM_DIRECT | STGM_READWRITE
  163.              | STGM_SHARE_EXCLUSIVE,
  164.            0,
  165.            &pIStorage);
  166.     if (SUCCEEDED(hr))
  167.     {
  168.       // We have created a new compound file. Now store the CLSID of
  169.       // COPageList.
  170.       hr = WriteClassStg(pIStorage, m_CidPageList);
  171.       if (SUCCEEDED(hr))
  172.       {
  173.         // Now Create the single "PageList" stream under the root storage.
  174.         hr = pIStorage->CreateStream(
  175.                PAGELIST_USTR,
  176.                STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  177.                0,
  178.                0,
  179.                &pIStream);
  180.         if (SUCCEEDED(hr))
  181.         {
  182.           // Now use the Class ID to create a COPageList object. Initially
  183.           // ask for the IPageList interface.
  184.           hr = CoCreateInstance(
  185.                  m_CidPageList,
  186.                  NULL,
  187.                  CLSCTX_INPROC_SERVER,
  188.                  IID_IPageList  ,
  189.                  (PPVOID)&pIPageList);
  190.           if (SUCCEEDED(hr))
  191.           {
  192.             // Clear the content of the Page List.
  193.             pIPageList->Clear();
  194.  
  195.             // Now obtain the IPersistStream interface on the new
  196.             // COPageList object. At this point the client assumes that
  197.             // PageList COM objects support the IPersistStream interface.
  198.             hr = pIPageList->QueryInterface(
  199.                    IID_IPersistStream,
  200.                    (PPVOID)&pIPersistStream);
  201.             if (SUCCEEDED(hr))
  202.             {
  203.               // And as expected by this client, COPageList supports
  204.               // the IPersistStream interface. Now use this interface
  205.               // to ask the COPageList object to save an empty Page List.
  206.  
  207.               // First ask the COPageList object how much space the
  208.               // maximum save would consume and then pre-allocate that
  209.               // space in the stream.
  210.               hr = pIPersistStream->GetSizeMax(&uliMaxSize);
  211.               if (SUCCEEDED(hr))
  212.               {
  213.                 hr = pIStream->SetSize(uliMaxSize);
  214.                 if (SUCCEEDED(hr))
  215.                 {
  216.                   // Now save the new Page List into the
  217.                   // pre-allocated space.
  218.                   hr = pIPersistStream->Save(pIStream, TRUE);
  219.                 }
  220.               }
  221.  
  222.               // Done with IPersistStream for now so release it.
  223.               pIPersistStream->Release();
  224.             }
  225.  
  226.             // Done with the stream for now so release it.
  227.             pIStream->Release();
  228.           }
  229.         }
  230.       }
  231.     }
  232.  
  233.     if (SUCCEEDED(hr))
  234.     {
  235.       // COPageList is fully created and the page list is
  236.       // loaded. Assign a copy of COPageList's IPageList
  237.       // interface for use by the caller.
  238.       *ppIPageList = pIPageList;
  239.  
  240.       // For performance, keep the Page List 'Document' file
  241.       // open (ie, don't release IStorage here) and give the
  242.       // caller a copy of the IStorage Pointer.
  243.       *ppIStorage = pIStorage;
  244.  
  245.       // The page list was loaded and we have a current compound
  246.       // file name. Copy it for later use in saves and loads.
  247.       if (bNewFile)
  248.         lstrcpy(m_szCurFileName, pszFileName);
  249.     }
  250.   }
  251.  
  252.   return (hr);
  253. }
  254.  
  255.  
  256. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  257.   Method:   CPageFile::Load
  258.  
  259.   Summary:  Load PageList data using the specified compound file name.
  260.             If this file is found then it is loaded. If it is not found
  261.             then an empty new file of the specified name is created.
  262.  
  263.   Args:     TCHAR* pszFileName,
  264.               Name/Path of the compound file to open. If NULL then use
  265.               CPageFile's m_szCurFileName as the compound file to load.
  266.             IStorage** ppIStorage,
  267.               Address of an IStorage pointer variable that will receive
  268.               the IStorage interface for the loaded PageList file.
  269.             IPageList** ppIPageList)
  270.               Address of an IPageList pointer variable that will receive
  271.               the IPageList interface for a new COPageList COM object.
  272.  
  273.   Returns:  HRESULT
  274.               Standard result code. NOERROR for success.
  275. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  276. HRESULT CPageFile::Load(
  277.           TCHAR* pszFileName,
  278.           IStorage** ppIStorage,
  279.           IPageList** ppIPageList)
  280. {
  281.   HRESULT hr = E_POINTER;
  282.   BOOL bNewFile = (NULL != pszFileName);
  283.   TCHAR* pszFile;
  284.   IStorage* pIStorage;
  285.   IStream* pIStream;
  286.   IPersistStream* pIPersistStream;
  287.   IPageList* pIPageList;
  288.   ULARGE_INTEGER uliMaxSize;
  289.  
  290.   if (NULL != ppIStorage && NULL != ppIPageList)
  291.   {
  292.     // Zero the output pointers in case of errror.
  293.     *ppIStorage = NULL;
  294.     *ppIPageList = NULL;
  295.  
  296.     // If NULL file name passed then use current file name.
  297.     pszFile = bNewFile ? pszFileName : m_szCurFileName;
  298.  
  299.     // Use COM service to check if the file is out there and is actually
  300.     // a valid compound file.
  301.     hr = StgIsStorageFile(pszFile);
  302.     if (SUCCEEDED(hr))
  303.     {
  304.       // We have a compound file. Use COM service to open the compound file
  305.       // and obtain a IStorage interface.
  306.       hr = StgOpenStorage(
  307.              pszFile,
  308.              NULL,
  309.              STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  310.              NULL,
  311.              0,
  312.              &pIStorage);
  313.       if (SUCCEEDED(hr))
  314.       {
  315.         // We have an IStorage. Now get the ClassID of the COM Server
  316.         // that handles Page Files.
  317.         hr = ReadClassStg(pIStorage, &m_CidPageList);
  318.         if (SUCCEEDED(hr))
  319.         {
  320.           // We have a ClassID for a server. Now Open the single "PageList"
  321.           // stream under the root storage.
  322.           hr = pIStorage->OpenStream(
  323.                  PAGELIST_USTR,
  324.                  0,
  325.                  STGM_READ | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  326.                  0,
  327.                  &pIStream);
  328.           if (SUCCEEDED(hr))
  329.           {
  330.             // Now use the previously obtained Class ID to create a
  331.             // COPageList object. Initially ask for IPageList interface.
  332.             hr = CoCreateInstance(
  333.                    m_CidPageList,
  334.                    NULL,
  335.                    CLSCTX_INPROC_SERVER,
  336.                    IID_IPageList  ,
  337.                    (PPVOID)&pIPageList);
  338.             if (SUCCEEDED(hr))
  339.             {
  340.               // We have a new COPageList object. Now obtain the
  341.               // IPersistStream interface on it. The client assumes at
  342.               // this point that PageList COM objects support only the
  343.               // IPersistStream interface for their persistence.
  344.               hr = pIPageList->QueryInterface(
  345.                      IID_IPersistStream,
  346.                      (PPVOID)&pIPersistStream);
  347.               if (SUCCEEDED(hr))
  348.               {
  349.                 // And as expected by this client, COPageList supports
  350.                 // the IPersistStream interface. Now use this interface
  351.                 // to ask the COPageList object to load the Page List.
  352.                 hr = pIPersistStream->Load(pIStream);
  353.  
  354.                 // Done with IPersistStream for now so release it.
  355.                 pIPersistStream->Release();
  356.               }
  357.               else
  358.                 pIPageList->Release();
  359.             }
  360.  
  361.             // Done with the stream for now so release it.
  362.             pIStream->Release();
  363.           }
  364.         }
  365.       }
  366.     }
  367.     else
  368.     {
  369.       // If there was no existing compound file use COM services to
  370.       // create a new compound file.
  371.       hr = StgCreateDocfile(
  372.              pszFile,
  373.              STGM_CREATE | STGM_DIRECT | STGM_READWRITE
  374.                | STGM_SHARE_EXCLUSIVE,
  375.              0,
  376.              &pIStorage);
  377.       if (SUCCEEDED(hr))
  378.       {
  379.         // We have created a new compound file. Now store the CLSID of
  380.         // COPageList.
  381.         hr = WriteClassStg(pIStorage, m_CidPageList);
  382.         if (SUCCEEDED(hr))
  383.         {
  384.           // Now Create the single "PageList" stream under the root storage.
  385.           hr = pIStorage->CreateStream(
  386.                  PAGELIST_USTR,
  387.                  STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  388.                  0,
  389.                  0,
  390.                  &pIStream);
  391.           if (SUCCEEDED(hr))
  392.           {
  393.             // Now use the Class ID to create a COPageList object. Initially
  394.             // ask for the IPageList interface.
  395.             hr = CoCreateInstance(
  396.                    m_CidPageList,
  397.                    NULL,
  398.                    CLSCTX_INPROC_SERVER,
  399.                    IID_IPageList  ,
  400.                    (PPVOID)&pIPageList);
  401.             if (SUCCEEDED(hr))
  402.             {
  403.               // We have a new COPageList object. Now obtain the
  404.               // IPersistStream interface on it. The client assumes at
  405.               // this point that PageList COM objects support only the
  406.               // IPersistStream interface for their persistence.
  407.               hr = pIPageList->QueryInterface(
  408.                    IID_IPersistStream,
  409.                      (PPVOID)&pIPersistStream);
  410.               if (SUCCEEDED(hr))
  411.               {
  412.                 // And as expected by this client, COPageList supports
  413.                 // the IPersistStream interface. Now use this interface
  414.                 // to ask the COPageList object to save an empty Page List.
  415.  
  416.                 // First ask the COPageList object how much space the
  417.                 // next save would consume and then pre-allocate that
  418.                 // space in the stream.
  419.                 hr = pIPersistStream->GetSizeMax(&uliMaxSize);
  420.                 if (SUCCEEDED(hr))
  421.                 {
  422.                   hr = pIStream->SetSize(uliMaxSize);
  423.                   if (SUCCEEDED(hr))
  424.                   {
  425.                     // Now save the new Page List into the
  426.                     // pre-allocated space.
  427.                     hr = pIPersistStream->Save(pIStream, TRUE);
  428.                   }
  429.                 }
  430.  
  431.                 // Done with IPersistStream for now so release it.
  432.                 pIPersistStream->Release();
  433.               }
  434.  
  435.               // Done with the stream for now so release it.
  436.               pIStream->Release();
  437.             }
  438.           }
  439.         }
  440.       }
  441.     }
  442.  
  443.     if (SUCCEEDED(hr))
  444.     {
  445.       // COPageList is fully created and the page list is
  446.       // loaded. Assign a copy of COPageList's IPageList
  447.       // interface for use by the caller.
  448.       *ppIPageList = pIPageList;
  449.  
  450.       // For performance, keep the Page List 'Document' file
  451.       // open (ie, don't release IStorage here) and give the
  452.       // caller a copy of the IStorage Pointer.
  453.       *ppIStorage = pIStorage;
  454.  
  455.       // The page list was loaded and we have a current compound
  456.       // file name. Copy it for later use in saves and loads.
  457.       if (bNewFile)
  458.         lstrcpy(m_szCurFileName, pszFileName);
  459.     }
  460.   }
  461.  
  462.   return (hr);
  463. }
  464.  
  465.  
  466. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  467.   Method:   CPageFile::Save
  468.  
  469.   Summary:  Save current pagelist data using the specified IStorage
  470.             and IPageList interfaces.
  471.  
  472.   Args:     IStorage* pIStorage,
  473.               Pointer to the opened file's IStorage interface.
  474.             IPageList* pIPageList)
  475.               Pointer to the IPageList interface on the COPageList object.
  476.  
  477.   Returns:  HRESULT
  478.               Standard result code. NOERROR for success.
  479. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  480. HRESULT CPageFile::Save(
  481.           IStorage* pIStorage,
  482.           IPageList* pIPageList)
  483. {
  484.   HRESULT hr = E_POINTER;
  485.   IStream* pIStream;
  486.   IPersistStream* pIPersistStream;
  487.  
  488.   if (NULL != pIStorage && NULL != pIPageList)
  489.   {
  490.     // Obtain the IPersistStream interface on the COPageList
  491.     // COM object.
  492.     hr = pIPageList->QueryInterface(
  493.            IID_IPersistStream,
  494.            (PPVOID)&pIPersistStream);
  495.     if (SUCCEEDED(hr))
  496.     {
  497.       // Save if the data is dirty (ie, doesn't match file data).
  498.       if (S_FALSE != pIPersistStream->IsDirty())
  499.       {
  500.         // Use the existing IStorage to Open the single "PageList" stream
  501.         // under the root storage.
  502.         hr = pIStorage->OpenStream(
  503.                PAGELIST_USTR,
  504.                0,
  505.                STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
  506.                0,
  507.                &pIStream);
  508.         if (SUCCEEDED(hr))
  509.         {
  510.           // Ask the persistent object to save itself in the stream
  511.           // and clear the PageList dirty bit.
  512.           hr = pIPersistStream->Save(pIStream, TRUE);
  513.  
  514.           // Done with the stream for now so release it.
  515.           pIStream->Release();
  516.         }
  517.       }
  518.  
  519.       // Done with IPersistStream for now so release it.
  520.       pIPersistStream->Release();
  521.     }
  522.   }
  523.  
  524.   return (hr);
  525. }
  526.  
  527.  
  528. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  529.   Method:   CPageFile::SaveAs
  530.  
  531.   Summary:  Create a new PageList compound file using the specified
  532.             file name. You must release the previous open IStorage prior
  533.             to calling this method.
  534.  
  535.   Args:     TCHAR* pszFileName,
  536.               Name/Path of the compound file to open. If NULL then use
  537.               CPageFile's m_szCurFileName as the compound file to load.
  538.             IPageList* pIPageList,
  539.               Pointer to the IPageList interface on the COPageList object.
  540.             IStorage** ppIStorage,
  541.               Address of an IStorage pointer variable that will receive
  542.               the IStorage interface for the new PageList file.
  543.  
  544.   Returns:  HRESULT
  545.               Standard result code. NOERROR for success.
  546. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  547. HRESULT CPageFile::SaveAs(
  548.           TCHAR* pszFileName,
  549.           IPageList* pIPageList,
  550.           IStorage** ppIStorage)
  551. {
  552.   HRESULT hr = E_POINTER;
  553.   BOOL bNewFile = (NULL != pszFileName);
  554.   IStorage* pIStorage;
  555.  
  556.   if (NULL != ppIStorage)
  557.   {
  558.     // Zero the output pointers in case of errror.
  559.     *ppIStorage = NULL;
  560.  
  561.     if (bNewFile)
  562.     {
  563.       // We have a compound file. Use COM service to reopen the
  564.       // compound file and obtain a IStorage interface.
  565.       hr = StgOpenStorage(
  566.              pszFileName,
  567.              NULL,
  568.              STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  569.              NULL,
  570.              0,
  571.              &pIStorage);
  572.       if (SUCCEEDED(hr))
  573.       {
  574.         // For performance, keep the Page List 'Document' file
  575.         // open (ie, don't release IStorage here) and give the
  576.         // caller a copy of the IStorage Pointer.
  577.         *ppIStorage = pIStorage;
  578.  
  579.         // Copy the new file name for later use in saves and loads.
  580.         lstrcpy(m_szCurFileName, pszFileName);
  581.       }
  582.     }
  583.   }
  584.  
  585.   return (hr);
  586. }
  587.