Figure 1   ShellExecute.cpp


/******************************************************************************
Module:  ShellExecute.cpp
Notices: Written by Jeffrey Richter
******************************************************************************/


#define STRICT
#include <Windows.h>


///////////////////////////////////////////////////////////////////////////////


int WINAPI _tWinMain (HINSTANCE, HINSTANCE, PSTR pCmdLine, int) {

   if ((int) ShellExecute(NULL, NULL, pCmdLine, 
      NULL, NULL, SW_SHOWNORMAL) <= 32) {

      // Error trying to run default browser, tell user
      TCHAR sz[1024];
      wsprintf(sz, TEXT("Error openning %s on CD-ROM disc."), pCmdLine);
      MessageBox(NULL, sz, TEXT("ShellExecute"), MB_OK | MB_ICONWARNING);
   } 

   return(0);
}


///////////////////////////////// End Of File /////////////////////////////////

Figure 2   GMMF.cpp

/*****************************************************************************
Module name: GMMF.cpp
Written by: Jeffrey Richter
Purpose:    Function prototypes for using growable memory-mapped files.
*****************************************************************************/

#define _WIN32_WINNT 0x0500 // Sparse files require Windows 2000
#include <windows.h>
#include <WinIoCtl.h>


//////////////////////////////////////////////////////////////////////////////


// This class makes it easy to work with memory-mapped sparse files
class CGMMF {
   HANDLE m_hfilemap;      // File-mapping object
   PVOID  m_pvFile;        // Address to start of mapped file

public:
   // Creates a GMMF and maps it in the process's address space.
   CGMMF(HANDLE hFile, UINT_PTR cbFileSizeMax);

   // Closes a GMMF
   ~CGMMF() { ForceClose(); }

   // GMMF to BYTE cast operator returns address of first byte 
   // in the memory-mapped sparse file. 
   operator PBYTE() const { return((PBYTE) m_pvFile); }

   // Allows you to explicitly close the GMMF without having
   // to wait for the destructor to be called.
   VOID ForceClose();

public:
    // Static method that resets a portion of a file back to
    // zeroes (frees disk clusters)
    static BOOL SetToZero(HANDLE hfile, 
        UINT_PTR cbOffsetStart, UINT_PTR cbOffsetEnd);
};


//////////////////////////////////////////////////////////////////////////////


CGMMF::CGMMF(HANDLE hfile, UINT_PTR cbFileSizeMax) {
    // Initialize to NULL in case something goes wrong
    m_hfilemap = m_pvFile = NULL;

    // Make the file sparse
    DWORD dw;
    BOOL fOk = ::DeviceIoControl(hfile, FSCTL_SET_SPARSE, 
        NULL, 0, NULL, 0, &dw, NULL);

    if (fOk) {
        // Create a file-mapping object
        m_hfilemap = ::CreateFileMapping(hfile, NULL, 
            PAGE_READWRITE, 0, cbFileSizeMax, NULL);

        if (m_hfilemap != NULL) {
            // Map the file into the process's address space
            m_pvFile = ::MapViewOfFile(m_hfilemap, 
                FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
        } else {
            // Failed to map the file, cleanup
            ForceClose();
        }
    }
}


//////////////////////////////////////////////////////////////////////////////


VOID CGMMF::ForceClose() {
    // Cleanup everything that was done sucessfully
    if (m_pvFile   != NULL) { 
        ::UnmapViewOfFile(m_pvFile); 
        m_pvFile = NULL; 
    }
    if (m_hfilemap != NULL) { 
        ::CloseHandle(m_hfilemap);   
        m_hfilemap = NULL; 
    }
}


//////////////////////////////////////////////////////////////////////////////


BOOL CGMMF::SetToZero(HANDLE hfile, 
    UINT_PTR cbOffsetStart, UINT_PTR cbOffsetEnd) {

    // NOTE: This function does not work if this file is memory-mapped.
    DWORD dw;
    FILE_ZERO_DATA_INFORMATION fzdi;
    fzdi.FileOffset.QuadPart = cbOffsetStart;
    fzdi.BeyondFinalZero.QuadPart = cbOffsetEnd + 1;
    return(::DeviceIoControl(hfile, FSCTL_SET_ZERO_DATA, 
        (LPVOID) &fzdi, sizeof(fzdi), NULL, 0, &dw, NULL));
}


//////////////////////////////////////////////////////////////////////////////


int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int ) {

    char szPathname[] = "C:\\GMMF.";

    // Create the file
    HANDLE hfile = CreateFile(szPathname, GENERIC_READ | GENERIC_WRITE, 
        0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // Create a GMMF using the file (set the maximum size here too)
    CGMMF gmmf(hfile, 10 * 1024 * 1024);

    // Read bytes from the file (0s are returned)
    for (int x = 0; x < 10 * 1024 * 1024; x += 1024) {
        if (gmmf[x] != 0) DebugBreak();
    }

    // Write bytes to the file (clusters are allocated as necessary).
    for (x = 0; x < 100; x++) {
        gmmf[8 * 1024 * 1024 + x] = x;
    }

    // These lines just prove to us what's going on
    DWORD dw = GetFileSize(hfile, NULL);
    // This returns the logical size of the file.

    // Get the actual number of bytes allocated in the file
    dw = GetCompressedFileSize(szPathname, NULL);
    // This returns 0 because the data has not been written to the file yet.
    
    // Force the data to be written to the file
    FlushViewOfFile(gmmf, 10 * 1024 * 1024);

    // Get the actual number of bytes allocated in the file
    dw = GetCompressedFileSize(szPathname, NULL);
    // This returns the size of a cluster now

    // Normally the destructor causes the file-mapping to close.
    // But, in this case, we wish to force it so that we can reset 
    // a portion of the file back to all zeroes.
    gmmf.ForceClose();

    // We call ForceClose above because attempting to zero a portion of the 
    // file while it is mapped, causes DeviceIoControl to fail with error 
    // code 0x4C8 (ERROR_USER_MAPPED_FILE: "The requested operation cannot 
    // be performed on a file with a user-mapped section open.")
    CGMMF::SetToZero(hfile, 0, 2 * 1024 * 1024);

    // We no longer need access to the file, close it.
    CloseHandle(hfile);

    return(0);
}

//////////////////////////////// End of File /////////////////////////////////