home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap07 / fragment / fragment.cpp next >
C/C++ Source or Header  |  1995-05-03  |  12KB  |  540 lines

  1. /*
  2.  * FRAGMENT.CPP
  3.  * Fragmented File Generator Chapter 7
  4.  *
  5.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  6.  *
  7.  * Kraig Brockschmidt, Microsoft
  8.  * Internet  :  kraigb@microsoft.com
  9.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  10.  */
  11.  
  12.  
  13. #include "fragment.h"
  14.  
  15.  
  16. /*
  17.  * WinMain
  18.  *
  19.  * Purpose:
  20.  *  Main entry point of application.  This application does nothing
  21.  *  more than pump out garbage into storage as a framented file test.
  22.  *  It has no UI so does not process any messages.
  23.  *
  24.  *  The file created is always called FRAGMENT.BIN.
  25.  */
  26.  
  27. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hInstPrev
  28.     , LPSTR pszCmdLine, int nCmdShow)
  29.     {
  30.     CFragment  *pFrag;
  31.  
  32.     pFrag=new CFragment();
  33.  
  34.     if (NULL==pFrag)
  35.         return -1;
  36.  
  37.     if (pFrag->Init())
  38.         {
  39.         if (pFrag->AllocCharArrays())
  40.             {
  41.             if (pFrag->CreateFragmentedFile())
  42.                 {
  43.                 pFrag->FreeSpaceInFile();
  44.                 pFrag->DefragmentFile();
  45.                 }
  46.             }
  47.         }
  48.  
  49.     delete pFrag;
  50.     return 0;
  51.     }
  52.  
  53.  
  54.  
  55.  
  56. /*
  57.  * CFragment::CFragment
  58.  * CFragment::~CFragment
  59.  *
  60.  * Constructor and Destructor for this application.  The
  61.  * constructor does not have any parameters.
  62.  */
  63.  
  64. CFragment::CFragment(void)
  65.     {
  66.     m_fInitialized=FALSE;
  67.     m_pIMalloc=NULL;
  68.     m_pch=NULL;
  69.     m_pszScratch=NULL;
  70.  
  71.     m_cch=256;
  72.     m_cStreams=CSTREAMS;
  73.  
  74.     lstrcpy(m_szFile, TEXT("FRAGMENT.BIN"));
  75.     m_hCur=NULL;
  76.  
  77.     return;
  78.     }
  79.  
  80.  
  81. CFragment::~CFragment(void)
  82.     {
  83.     if (NULL!=m_hCur)
  84.         SetCursor(m_hCur);
  85.  
  86.     if (NULL!=m_pIMalloc)
  87.         {
  88.         if (NULL!=m_pch)
  89.             m_pIMalloc->Free(m_pch);
  90.  
  91.         if (NULL!=m_pszScratch)
  92.             m_pIMalloc->Free(m_pszScratch);
  93.  
  94.         m_pIMalloc->Release();
  95.         }
  96.  
  97.     if (m_fInitialized)
  98.         CoUninitialize();
  99.  
  100.     return;
  101.     }
  102.  
  103.  
  104.  
  105.  
  106. /*
  107.  * CFragment::Init
  108.  *
  109.  * Purpose:
  110.  *  Calls CoInitialize and CoGetMalloc saving the task allocator.
  111.  *
  112.  * Parameters:
  113.  *  None
  114.  *
  115.  * Return Value:
  116.  *  BOOL            TRUE if initialization worked, FALSE otherwise.
  117.  */
  118.  
  119. BOOL CFragment::Init(void)
  120.     {
  121.     CHECKVER_COM;
  122.  
  123.     if (FAILED(CoInitialize(NULL)))
  124.         return FALSE;
  125.  
  126.     m_fInitialized=TRUE;
  127.  
  128.     if (FAILED(CoGetMalloc(MEMCTX_TASK, &m_pIMalloc)))
  129.         return FALSE;
  130.  
  131.     m_pszScratch=(TCHAR *)m_pIMalloc->Alloc(1024*sizeof(TCHAR));
  132.  
  133.     if (NULL==m_pszScratch)
  134.         return FALSE;
  135.  
  136.     m_hCur=SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)));
  137.     return TRUE;
  138.     }
  139.  
  140.  
  141.  
  142. /*
  143.  * CFragmet::AllocCharArrays
  144.  *
  145.  * Purpose:
  146.  *  Allocates CSTREAMS * 256 characters and initializes each 256
  147.  *  charaters with 'A', 'B', etc.  (ANSI characters, not UNICODE).
  148.  *
  149.  * Parameters:
  150.  *  None
  151.  *
  152.  * Return Value:
  153.  *  BOOL            TRUE if the memory was allocated and initialized
  154.  *                  otherwise FALSE.
  155.  */
  156.  
  157. BOOL CFragment::AllocCharArrays(void)
  158.     {
  159.     char *      pchT;
  160.     UINT        i, j;
  161.  
  162.     if (NULL==m_pIMalloc)
  163.         return FALSE;
  164.  
  165.     m_pch=(char *)m_pIMalloc->Alloc(m_cch*m_cStreams);
  166.  
  167.     if (NULL==m_pch)
  168.         return FALSE;
  169.  
  170.     pchT=m_pch;
  171.  
  172.     //Initialize Character Arrays
  173.     for (i=0; i < m_cStreams; i++)
  174.         {
  175.         char    ch=i+'A';
  176.  
  177.         for (j=0; j < m_cch; j++)
  178.             *pchT++=ch;
  179.         }
  180.  
  181.     return TRUE;
  182.     }
  183.  
  184.  
  185.  
  186.  
  187. /*
  188.  * CFragment::CreateFragmentedFile
  189.  *
  190.  * Purpose:
  191.  *  Creates a file with numerous streams that we can fragment.
  192.  *
  193.  * Parameters:
  194.  *  None
  195.  *
  196.  * Return Value:
  197.  *  BOOL            TRUE if the file was created, FALSE otherwise.
  198.  */
  199.  
  200. BOOL CFragment::CreateFragmentedFile(void)
  201.     {
  202.     HRESULT     hr;
  203.     IStorage   *pIStorage;
  204.     IStream    *rgpIStream[CSTREAMS];
  205.     UINT        i, j;
  206.  
  207.     //Create the file to build
  208.     hr=StgCreateDocfile(m_szFile, STGM_DIRECT | STGM_READWRITE
  209.         | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, &pIStorage);
  210.  
  211.     if (FAILED(hr))
  212.         return FALSE;
  213.  
  214.     //Create streams in this file.
  215.     for (i=0; i < m_cStreams; i++)
  216.         StreamCreate(pIStorage, i, &rgpIStream[i]);
  217.  
  218.     /*
  219.      * Now fill "Stream A" with A's, Stream B with B's, etc.,
  220.      * doing it m_cch characters at a time, a total of 20 times for
  221.      * each stream.  This will allow us to examine the binary
  222.      * format of the file before and after defragmentation.
  223.      *
  224.      * This will create a number of streams that are internally
  225.      * fragmented in the file.
  226.      *
  227.      * Some streams may be invalid, but checks for NULL below
  228.      * avoid problems in such cases.
  229.      */
  230.  
  231.     for (j=0; j < 20; j++)
  232.         {
  233.         for (i=0; i < m_cStreams; i++)
  234.             {
  235.             if (NULL!=rgpIStream[i])
  236.                 rgpIStream[i]->Write((m_pch+(m_cch*i)), m_cch, NULL);
  237.             }
  238.         }
  239.  
  240.     //Close all the streams
  241.     for (i=0; i < m_cStreams; i++)
  242.         {
  243.         if (NULL!=rgpIStream[i])
  244.             rgpIStream[i]->Release();
  245.         }
  246.  
  247.     //Close the IStorage to close the file.
  248.     pIStorage->Release();
  249.  
  250.     Message(TEXT("%s created."));
  251.     return TRUE;
  252.     }
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260. /*
  261.  * CFragment::FreeSpaceInFile
  262.  *
  263.  * Purpose:
  264.  *  Deletes some of the streams in the previously created file.
  265.  *
  266.  * Parameters:
  267.  *  None
  268.  *
  269.  * Return Value:
  270.  *  None
  271.  */
  272.  
  273. void CFragment::FreeSpaceInFile(void)
  274.     {
  275.     HRESULT     hr;
  276.     IStorage   *pIStorage;
  277.  
  278.     //Reopen the storage
  279.     hr=StgOpenStorage(m_szFile, NULL, STGM_DIRECT | STGM_READWRITE
  280.         | STGM_SHARE_EXCLUSIVE, NULL, 0, &pIStorage);
  281.  
  282.     if (SUCCEEDED(hr))
  283.         {
  284.         /*
  285.          * Now create some extra space in the file by destroying
  286.          * streams C E G H J M N T X.
  287.          */
  288.         pIStorage->DestroyElement(OLETEXT("Stream C"));
  289.         pIStorage->DestroyElement(OLETEXT("Stream E"));
  290.         pIStorage->DestroyElement(OLETEXT("Stream G"));
  291.         pIStorage->DestroyElement(OLETEXT("Stream H"));
  292.         pIStorage->DestroyElement(OLETEXT("Stream J"));
  293.         pIStorage->DestroyElement(OLETEXT("Stream M"));
  294.         pIStorage->DestroyElement(OLETEXT("Stream N"));
  295.         pIStorage->DestroyElement(OLETEXT("Stream T"));
  296.         pIStorage->DestroyElement(OLETEXT("Stream X"));
  297.  
  298.         /*
  299.          * The file size will not have changed here, but there
  300.          * will be unused space.
  301.          */
  302.  
  303.         pIStorage->Release();
  304.         Message(TEXT("Space has been freed in %s."));
  305.         }
  306.     else
  307.         Message(TEXT("Could not reopen %s."));
  308.  
  309.     return;
  310.     }
  311.  
  312.  
  313.  
  314.  
  315.  
  316. /*
  317.  * CFragment::DefragmentFile
  318.  *
  319.  * Purpose:
  320.  *  Does an IStorage::CopyTo from the existing file to a temp
  321.  *  file then copies that temp file as binary back to the source
  322.  *  file.
  323.  *
  324.  * Parameters:
  325.  *  None
  326.  *
  327.  * Return Value:
  328.  *  None
  329.  */
  330.  
  331. void CFragment::DefragmentFile(void)
  332.     {
  333.     HRESULT     hr;
  334.     IStorage   *pIStorageOld;
  335.     IStorage   *pIStorageNew;
  336.     STATSTG     st;
  337.    #ifndef WIN32
  338.     OFSTRUCT    of;
  339.    #endif
  340.     TCHAR       szTemp[MAX_PATH];
  341.  
  342.     /*
  343.      * Create a temporary file.  We don't use DELETEONRELEASE
  344.      * in case we have to save it when copying over the old
  345.      * file fails.
  346.      */
  347.     hr=StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE
  348.         | STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &pIStorageNew);
  349.  
  350.     if (FAILED(hr))
  351.         {
  352.         Message(TEXT("Failed to create temp file to copy %s."));
  353.         return;
  354.         }
  355.  
  356.     //Open the existing file as read-only
  357.     hr=StgOpenStorage(m_szFile, NULL, STGM_DIRECT | STGM_READ
  358.         | STGM_SHARE_DENY_WRITE, NULL, 0, &pIStorageOld);
  359.  
  360.     if (FAILED(hr))
  361.         {
  362.         pIStorageNew->Release();
  363.         Message(TEXT("Failed to open %s for CopyTo."));
  364.         return;
  365.         }
  366.  
  367.     /*
  368.      * Compress with CopyTo.  Since the temp is opened in
  369.      * direct mode, changes are immediate.
  370.      */
  371.     hr=pIStorageOld->CopyTo(NULL, NULL, NULL, pIStorageNew);
  372.     pIStorageOld->Release();
  373.  
  374.     if (FAILED(hr))
  375.         {
  376.         pIStorageNew->Release();
  377.         Message(TEXT("IStorage::CopyTo from %s failed."));
  378.         return;
  379.         }
  380.  
  381.     //Get the name of the temp file.
  382.     pIStorageNew->Stat(&st, 0);
  383.     pIStorageNew->Release();
  384.  
  385.     //Delete the old file before copying back to insure truncation
  386.    #ifdef WIN32
  387.     DeleteFile(m_szFile);
  388.  
  389.    #ifdef WIN32ANSI
  390.     WideCharToMultiByte(CP_ACP, 0, st.pwcsName, -1, szTemp
  391.         , MAX_PATH, NULL, NULL);
  392.    #else
  393.     lstrcpy(szTemp, st.pwcsName);
  394.    #endif
  395.  
  396.     MoveFile(szTemp, m_szFile);
  397.    #else
  398.     OpenFile(m_szFile, &of, OF_DELETE);
  399.     MyMoveFile(st.pwcsName, m_szFile);
  400.    #endif
  401.  
  402.     Message(TEXT("Defragementation complete on %s."));
  403.     return;
  404.     }
  405.  
  406.  
  407.  
  408.  
  409. /*
  410.  * CFragment::StreamCreate
  411.  *
  412.  * Purpose:
  413.  *  Creates a stream with a given identifier in a given IStorage.
  414.  *
  415.  * Parameters:
  416.  *  pIStorage       IStorage * in which to create the stream
  417.  *  i               UINT ID of the stream
  418.  *  ppIStream       IStream ** in which to return the stream.
  419.  *
  420.  * Return Value:
  421.  *  None
  422.  */
  423.  
  424. void CFragment::StreamCreate(IStorage *pIStorage, UINT i
  425.     , IStream ** ppIStream)
  426.     {
  427.     OLECHAR  szName[40];
  428.  
  429.     //Name is "Stream A", "Stream B", etc.
  430.    #ifdef WIN32ANSI
  431.     char        szTemp[40];
  432.  
  433.     wsprintf(szTemp, "Stream %c", i+'A');
  434.     MultiByteToWideChar(CP_ACP, 0, szTemp, -1, szName, 40);
  435.    #else
  436.     wsprintf(szName, TEXT("Stream %c"), i+'A');
  437.    #endif
  438.  
  439.     pIStorage->CreateStream(szName, STGM_DIRECT
  440.         | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  441.         , 0, 0, ppIStream);
  442.  
  443.     return;
  444.     }
  445.  
  446.  
  447.  
  448. /*
  449.  * CFragment::Message
  450.  *
  451.  * Purpose:
  452.  *  Outputs a message with the filename included.
  453.  *
  454.  * Parameters:
  455.  *  pszFmt          LPTSTR to a wsprintf format string.
  456.  *
  457.  * Return Value:
  458.  *  None
  459.  */
  460.  
  461. void CFragment::Message(LPTSTR pszFmt)
  462.     {
  463.     wsprintf(m_pszScratch, pszFmt, m_szFile);
  464.     MessageBox(NULL, m_pszScratch, TEXT("Fragmenter"), MB_OK);
  465.     return;
  466.     }
  467.  
  468.  
  469.  
  470.  
  471.  
  472. #ifndef WIN32
  473. /*
  474.  * CFragment::MyMoveFile
  475.  *
  476.  * Purpose:
  477.  *  Low-level MoveFile function for 16-bit Windows that lack
  478.  *  the MoveFile[Ex] API.
  479.  *
  480.  * Parameters:
  481.  *  pszSrc          char * of the source filename,
  482.  *  pszDst          char * of the destination filename,
  483.  *
  484.  * Return Value:
  485.  *  None
  486.  */
  487.  
  488. void CFragment::MyMoveFile(char *pszSrc, char *pszDst)
  489.     {
  490.     HFILE       hFile1, hFile2;
  491.     ULONG       cbCopy;
  492.     const UINT  cbBlock=4096;
  493.     LPBYTE      pb;
  494.     OFSTRUCT    of;
  495.  
  496.     //Do a binary copy between files.
  497.     hFile1=_lopen(pszSrc, READ | OF_SHARE_EXCLUSIVE);
  498.  
  499.     if (HFILE_ERROR==hFile1)
  500.         return;
  501.  
  502.     //Recreate this file before copying.
  503.     hFile2=_lcreat(m_szFile, 0);
  504.  
  505.     if (HFILE_ERROR==hFile2)
  506.         {
  507.         _lclose(hFile1);
  508.         return;
  509.         }
  510.  
  511.     //Seek to end of source file to find length
  512.     cbCopy=_llseek(hFile1, 0, 2);
  513.     _llseek(hFile1, 0, 0);
  514.  
  515.     pb=(LPBYTE)m_pIMalloc->Alloc(cbBlock);
  516.  
  517.     if (NULL!=pb)
  518.         {
  519.         //Copy in 4K increments
  520.         while (cbCopy >= (ULONG)cbBlock)
  521.             {
  522.             _lread(hFile1,  pb, cbBlock);
  523.             _lwrite(hFile2, pb, cbBlock);
  524.             cbCopy-=4096;
  525.             }
  526.  
  527.         _lread(hFile1,  pb, (UINT)cbCopy);
  528.         _lwrite(hFile2, pb, (UINT)cbCopy);
  529.         m_pIMalloc->Free(pb);
  530.         }
  531.  
  532.     _lclose(hFile2);
  533.     _lclose(hFile1);
  534.  
  535.     //Delete the temp file
  536.     OpenFile(pszSrc, &of, OF_DELETE);
  537.     return;
  538.     }
  539. #endif
  540.