/******************************************************************************
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 /////////////////////////////////