Getting and Setting File Information

< BACK  NEXT >
[oR]

The Windows CE API contains several functions that are useful for retrieving file information. For example, you can find out when a file was last modified, how its attribute bits are currently set, and the size of the file. The following sections detail the different capabilities that are available. Several of these functions require an open file handle rather than the file's name.

Getting the File Times

The GetFileTime function retrieves three different pieces of time information from an open file: the Creation time, the Last Access time, and the Last Write time.

Table 2.4. GetFileTime Gets file time information
GetFileTime
HANDLE file Handle to a file from CreateFile
LPFILETIME creationTime Time of file creation
LPFILETIME lastAccessTime Time of last file access
LPFILETIME lastWriteTime Time of last file write
BOOL Return Value Returns TRUE on success, otherwise FALSE

In Listing 2.3, the CreateFile function opens the requested file name. GetFileTime uses the handle that it returns to access the file times, and then passes the last write time up to the ShowTime function to dump the time to cout.

Listing 2.3 Displays the file times associated with the given file
 void ShowTime(FILETIME t) {   FILETIME ft;   SYSTEMTIME st;   FileTimeToLocalFileTime(&t, &ft);   FileTimeToSystemTime(&ft, &st);   cout   st.wMonth   _T("/")   st.wDay               _T("/")   st.wYear   _T(" ")   st.wHour               _T(":")   st.wMinute   endl; } void Listing2_3() {   HANDLE hFile;   TCHAR szFilename[MAX_PATH + 1];   FILETIME ftCreate, ftLastWrite, ftLastAccess;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   hFile = CreateFile(szFilename,       GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout    _T("Could not open file. Error:")             GetLastError();     return;   }   if(GetFileTime(hFile, &ftCreate,     &ftLastWrite, &ftLastAccess))   {     cout   _T("Create time: ");     ShowTime(ftCreate);     cout   _T("Last write time: ");     ShowTime(ftLastWrite);     cout   _T("Last Access time: ");     ShowTime(ftLastAccess);   }   else     cout   _T("Could not file times. Error: ")            GetLastError();   CloseHandle(hFile); } 

FILETIME is a structure that contains two 32-bit values. The 64 bits together represent the number of 100-nanosecond time increments that have passed since January1, 1601. The FileTimeToLocalTime and FileTimeToSystemTime functions convert the 64-bit value to local time and then to a form suitable for output. The times returned by GetFileTime are in UTC (Universal Coordinated Time, otherwise known as Greenwich Mean Time or GMT), and so should be converted to local time when displayed to users.

The function SetFileTime can be used to set one or all of the three file times. Note that when changing just one of the times on an object store file, the other two file times are updated by default. This behavior does not occur with FAT files.

Getting File Size

The GetFileSize function returns the size of the file in bytes, or 0xFFFFFFFF on error. The file size returned is the uncompressed file size files in the object store are automatically compressed. In the Object Store the largest file size possible can be represented in less than 32 bits, but NTFS (which you may connect to through the network) is a 64-bit file system. GetFileSize therefore returns 64 bits of size information if you request it. There is currently no easy way to deal with integers larger than 32bits.

Table 2.5. GetFileSize Returns a 64-bit size value for the file
GetFileSize
HANDLE file Handle to a file from CreateFile
LPDWORD fileSizeHigh Pointer to a DWORD that returns the high-order 32 bits of size
Return Value Returns the low-order 32 bits of the file size, or 0xFFFFFFFF on failure

The low-order 32 bits of size information comes from the return value, while the high-order 32 bits come from the fileSizeHigh parameter when you pass in a pointer to a DWORD. You can also pass in NULL for this parameter if you are not interested in receiving the high-order 32 bits of information. Listing 2.4 shows how to access the information.

Listing 2.4 Reports size of file in bytes
 void Listing2_4() {   HANDLE hFile;   TCHAR szFilename[MAX_PATH + 1];   DWORD dwSizeLo, dwSizeHi;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   hFile = CreateFile(szFilename, GENERIC_READ,       0, 0, OPEN_EXISTING, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout   _T("Could not open file. Error:")            GetLastError();     return;   }     dwSizeLo = GetFileSize (hFile, &dwSizeHi);   if(dwSizeLo == 0xFFFFFFFF && GetLastError()             != NO_ERROR)     cout    _T("Error getting file size: ")             GetLastError();   else     cout    _T("Filesize (Low, High) : ")   dwSizeLo  _T(",")   dwSizeHi;   CloseHandle(hFile); } 

Getting File Attributes

Files have associated with them attribute bits that hold special information about the file. You can view most of the attributes from the Explorer by selecting a file and then choosing the Properties option in the File menu. Inside a program you can examine attribute bits with the GetFileAttributes function.

Table 2.6. GetFileAttributes Gets the attribute bits for a file
GetFileAttributes
LPTSTR fileName The name of the file
Return Value Returns the attribute bits as a DWORD, or 0xFFFFFFFF on error

Listing 2.5 demonstrates how to acquire and examine the attribute bits. The system returns not only the four standard bits seen in the Explorer (archive, read only, system, and hidden), but also bits indicating that the file name is actually a directory, as well as In-ROM and related attributes. Note that not all the available attributes are listed in the code sample.

Listing 2.5 Reports file attributes
 void ShowAttributes(DWORD dwAttributes) {   if(dwAttributes & FILE_ATTRIBUTE_READONLY)     cout   _T("Read only")   endl;   if(dwAttributes & FILE_ATTRIBUTE_HIDDEN)     cout   _T("Hidden")   endl;   if(dwAttributes & FILE_ATTRIBUTE_SYSTEM)     cout   _T("System")   endl;   if(dwAttributes & FILE_ATTRIBUTE_DIRECTORY)     cout   _T("Directory")   endl;   if(dwAttributes & FILE_ATTRIBUTE_ARCHIVE)     cout   _T("Archive")   endl;   if(dwAttributes & FILE_ATTRIBUTE_INROM)     cout   _T("In ROM")   endl;   if(dwAttributes & FILE_ATTRIBUTE_NORMAL)     cout   _T("Normal")   endl;   if(dwAttributes & FILE_ATTRIBUTE_TEMPORARY)     cout   _T("Temporary")   endl;   if(dwAttributes & FILE_ATTRIBUTE_COMPRESSED)     cout   _T("Compressed")   endl;   if(dwAttributes & FILE_ATTRIBUTE_ROMSTATICREF)     cout   _T("ROM Static Ref")   endl;   if(dwAttributes & FILE_ATTRIBUTE_ROMMODULE)     cout   _T("ROM Module")   endl; } void Listing2_5() {   TCHAR szFilename[MAX_PATH + 1];   DWORD dwAttributes;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   dwAttributes = GetFileAttributes(szFilename);   ShowAttributes(dwAttributes); } 

It is also possible to set some file attributes using the SetFileAttributes function. This function accepts a file name and one or more attribute constants, and returns a Boolean value indicating success or failure.

Table 2.7. SetFileAttributes Sets file attributes
SetFileAttributes
LPTSTR filename The name of the file
DWORD attributes Attributes as for GetFileAttributes
Return Value Returns TRUE on success, otherwise FALSE

The same attribute constants seen in the ShowAttributes function of Listing 2.5 are available. For example, you might set a file as hidden and read-only with the following statement:

 success = SetFileAttributes(_T("xxx"),   FILE_ATTRIBUTE_HIDDEN |   FILE_ATTRIBUTE_READONLY); 

Generally those are the only two attributes you will want to set. The other bits, for example the directory bit, are set automatically by system calls when they are appropriate and should not be altered. File attributes can be set when the file is created using CreateFile. Table 2.8 shows the Windows CE file attributes; indicates whether they can be accessed using GetFileAttributes, SetFileAttributes, and CreateFile; and gives a brief definition.

Table 2.8. File Attributes and Their Purposes
Attribute Purpose
FILE_ATTRIBUTE_ARCHIVE File has been archived or backed up.
FILE_ATTRIBUTE_COMPRESSED File is stored in compressed format.
FILE_ATTRIBUTE_DIRECTORY File is a directory.
FILE_ATTRIBUTE_ENCRYPTED File is encrypted.
FILE_ATTRIBUTE_HIDDEN File is hidden and not included in normal directory listings.
FILE_ATTRIBUTE_INROM File is located in ROM. It is read-only and cannot be modified.
FILE_ATTRIBUTE_NORMAL Normal file, has no other attributes.
FILE_ATTRIBUTE_OFFLINE File contents not currently available.
FILE_ATTRIBUTE_READONLY File is read-only.
FILE_ATTRIBUTE_REPARSE_POINT The file has an associated reparse point.
FILE_ATTRIBUTE_ROMMODULE DLL or EXE in ROM. CreateFile cannot be used to access these files.
FILE_ATTRIBUTE_SPARSE_FILE Empty spaces in a file are not stored.
FILE_ATTRIBUTE_SYSTEM File is part of the system file set.
FILE_ATTRIBUTE_TEMPORARY Temporary file, will be deleted.
FILE_FLAG_WRITE_THROUGH No buffering for file I/O.
FILE_FLAG_RANDOM_ACCESS Open optimized for random access.
FILE_FLAG_SEQUENTIAL_SCAN Open optimized for sequential option.
FILE_ATTRIBUTE_ROMSTATICREF Module is in ROM and contains static references to other modules. It cannot be replaced (shadowed) with a file in RAM.

All files in the object store are compressed, and will have the FILE_ATTRIBUTE_COMPRESSED attribute. You cannot set this attribute to compress a file as you can with Windows NT and 2000.

Getting All File Information

The function GetFileInformationByHandle returns all of the information described in the previous three sections in one call. It is useful when you want to access or display all information about a file in one call.

Table 2.9. GetFileInformationByHandle Retrieves all file information
GetFileInformationByHandle
HANDLE file Handle to an open file from CreateFile
LPBY_HANDLE_FILE_INFORMATION Information about the file
Return Value Returns TRUE on success, otherwise FALSE

The information comes back in a structure that contains the attributes, size, and time data discussed in the previous sections, along with volume, index, and link information not available anywhere else. The volume serial number is a unique number assigned to the volume when it was formatted. The file index is a unique identifier attached to the file while it is open. Listing 2.6 demonstrates the process.

Listing 2.6 Lists all information for a given file
 void Listing2_6() {   HANDLE hFile;   TCHAR szFilename[MAX_PATH + 1];   BY_HANDLE_FILE_INFORMATION fiInfo;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   hFile = CreateFile(szFilename, GENERIC_READ,       0, 0, OPEN_EXISTING, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout   _T("Could not open file. Error:")            GetLastError();     return;   }   if(GetFileInformationByHandle(hFile, &fiInfo))   {     ShowAttributes(fiInfo.dwFileAttributes);     cout   _T("Create time: ");     ShowTime(fiInfo.ftCreationTime);     cout   _T("Last write time: ");     ShowTime(fiInfo.ftLastWriteTime);     cout   _T("Last Access time: ");     ShowTime(fiInfo.ftLastAccessTime);     cout    _T("Volume serial number: ")  fiInfo.dwVolumeSerialNumber   endl;     cout    _T("File size: ")   fiInfo.nFileSizeLow   endl;     cout    _T("High index: ")   fiInfo.nFileIndexHigh   endl;     cout    _T("Low index: ")   fiInfo.nFileIndexLow   endl;     cout    _T("Object ID: ")   fiInfo.dwOID   endl;   }   CloseHandle(hFile); } 

File Operations

The API provides three functions for the common file operations of moving, copying, and deleting files. You can use these functions in your programs to duplicate the functionality of the command line equivalents.

The CopyFile function copies the source file to the destination file name. If an error occurs during the copy, GetLastError contains the error code.

Table 2.10. CopyFile Copies a file
CopyFile
LPTSTR sourceFile File name for the source file.
LPTSTR destFile File name for the destination.
BOOL existFail Passing TRUE causes the call to fail if the file exists. FALSE allows existing files to be overwritten.
BOOL Return Value TRUE on success, otherwise FALSE.

The existFail parameter controls the behavior of the function when the destination file name already exists. If you set it to TRUE, then the function fails when the destination file name already exists. When set to FALSE, the function overwrites an existing file. This code fragment demonstrates the use of this function.

   success = CopyFile(sourceFilename,       destFilename, TRUE);   if (!success)     cout   _T("Error code = ")   GetLastError();   else     cout   _T("success\n"); 

Files can be deleted using the DeleteFile function, which is passed the filename to be deleted (Table 2.11).

If the return value is FALSE, use the GetLastError function to retrieve the error code, as shown in this code fragment.

Table 2.11. DeleteFile Deletes a file
DeleteFile
LPTSTR fileName Filename to delete
Return Value Returns TRUE on success, FALSE on failure.

   success = DeleteFile(filename);   if (success)     cout   _T("success\n");   else     cout   _T("Error number: ") "   GetLastError(); 

File Reading and Writing

The section "Opening and Reading from a File" in this chapter briefly introduced simple file reading using CreateFile, ReadFile, and CloseHandle. In this section we will examine file seeking, reading, and writing in more detail, and look at the CreateFile function more carefully. The operations here are all synchronous, so they block (that is, do not return) until complete. Asynchronous file operations are not supported in Windows CE. Listing 2.7 demonstrates a file-write operation that writes structures to a new file.

Listing 2.7 Writes structures to a file
 typedef struct {   int a, b, c; } DATA; void Listing2_7() {   HANDLE hFile;   TCHAR szFilename[MAX_PATH + 1];   BOOL bSuccess;   DATA dataRec;   int x;   DWORD numWrite;   if(!GetFilename(_T("Enter filename to create:"),          szFilename, MAX_PATH, TRUE))     return;   cout   szFilename;   hFile = CreateFile(szFilename,       GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout    _T("Could not open file. Error:")             GetLastError();     return;   }     = 0;   do   {     dataRec.a = dataRec.b = dataRec.c = x;     bSuccess = WriteFile(hFile, &dataRec,          sizeof(dataRec), &numWrite, 0);   }   while(bSuccess && x++  10);   CloseHandle(hFile); } 

The WriteFile function is similar to the ReadFile function, writing the specified number of bytes to disk. The function does not care what the bytes represent, so you can use it to write text or structures. In Listing 2.7, the program writes one structure's set of bytes in a single operation and repeats the operation ten times.

Table 2.12. WriteFile Writes data to a file
WriteFile
HANDLE fileHandle Handle to a file created by CreateFile
CONST VOID *buffer Data to write
DWORD bytesToWrite The number of bytes to write
LPDWORD bytesWritten Pointer to a DWORD that returns the number of bytes actually written
LPOVERLAPPED overlapped Overlapped structure (not supported, pass as NULL)
BOOL Return Value TRUE for success, FALSE for failure

Listing 2.7 uses the CreateFile function in its simplest configuration. For example, in Listing 2.7 the GENERIC_WRITE constant indicates that we need write access to the file, and the CREATE_NEW constant indicates that the system should create a new file rather than overwrite an existing one (if the file name already exists, the function fails). However, CreateFile has many other capabilities.

When using the CreateFile function, you have control over several different properties:

  • The read and write mode

  • The way the file will be shared

  • A variety of attributes and performance hints

Table 2.13. CreateFile Creates a new file or opens an existing file
CreateFile
LPCTSTR name Name of the file to open
DWORD accessMode Read/Write mode
DWORD shareMode The way the file should be shared
LPSECURITY_ATTRIBUTES securityAttributes Address of a security structure (not supported, pass as NULL)
DWORD create The way the file should be created
DWORD attributes Settings for normal file attribute bits
HANDLE templateFile File containing extended attributes (not supported, pass as NULL)
HANDLE Return Value Returns a handle to the file, or INVALID_HANDLE_VALUE on failure

The first parameter contains the name of the file to be opened. The function GetTempFileName can be used to obtain a valid temporary filename from the operating system. The second parameter passed to CreateFile controls read and write access. You can pass in any of the following three combinations:

Table 2.14. Read/write access control
Constant Purpose
GENERIC_READ Read only
GENERIC_WRITE Write only
GENERIC_READ | GENERIC_WRITE Read/write

Generally you use the third option when you plan to open a file of structures that you will read and modify simultaneously. You use GENERIC_READ when you want read-only access, and GENERIC_WRITE when you need write-only access.

The third parameter passed to CreateFile controls the share mode of the file. You control access to the entire file using this parameter. Four variations are possible (Table 2.15).

Table 2.15. Share mode options
Constant Purpose
0 Exclusive use of the file
FILE_SHARE_READ Read-sharing of the file
FILE_SHARE_WRITE Write-sharing of the file
FILE_SHARE_READ | FILE_SHARE_WRITE Read/Write sharing

If you pass 0 to the shareMode parameter, then the entire file is locked while you have it open. Any other process attempting to open the file will receive a share violation. The remaining options grant increasing levels of access to other processes.

The Create parameter controls the failure behavior of CreateFile during creation. Any of the options in Table 2.16 may be used. If you create a new file with the same name as a file in ROM, the ROM file will be "shadowed." Your new file will replace the ROM file. If your file is deleted, the ROM file comes back into use.

Table 2.16. Create Parameters
Constant Purpose
CREATE_NEW Create a new file. Fails if file name exists.
CREATE_ALWAYS Create a new file. Destroys any existing file.
OPEN_EXISTING Opens an existing file. Fails if file not found.
OPEN_ALWAYS Creates a file if one does not exist, or opens the existing file.
TRUNCATE_EXISTING Deletes the contents of the file if it exists. Fails if it does not exist.

The Attributes parameter lets you set the file attributes, and it also lets you tell the system your intended use of the file so that you can improve overall system performance. Table 2.17 shows all the available attributes and indicates which ones can be used in CreateFile, GetFileAttributes, and SetFileAttributes. Table 2.8 provides a description of the attributes. You can OR together nonconflicting combinations shown in Table 2.17 as needed in an application.

Many of the flag options are hints that you give to help the operating system improve its overall performance. For example, if you know you are opening a 1-MB file that you will read from beginning to end and never use again, then it is a waste for the operating system to cache any of it. You should therefore use the FILE_FLAG_SEQUENTIAL_SCAN option.

It is possible to read from or write to a file either sequentially or at random byte offsets in the file. You typically use random offsets when the file contains a set of structures. The SetFilePointer function moves the file pointer to the indicated position.

The new file position can move a distance that is relative to the beginning of the file, the end of the file, or the current position. Positive values move forward, and negative values move backward. Listing 2.8 demonstrates a program that sets the file pointer to the fifth structure in the file written by Listing 2.7.

Table 2.17. File Attributes
Attribute Create-File GetFile-Attributes SetFile-Attribute
FILE_ATTRIBUTE_ARCHIVE X X X
FILE_ATTRIBUTE_COMPRESSED X
FILE_ATTRIBUTE_DIRECTORY X
FILE_ATTRIBUTE_ENCRYPTED X
FILE_ATTRIBUTE_HIDDEN X X X
FILE_ATTRIBUTE_INROM X
FILE_ATTRIBUTE_NORMAL X X X
FILE_ATTRIBUTE_OFFLINE X X
FILE_ATTRIBUTE_READONLY X X X
FILE_ATTRIBUTE_REPARSE_POINT X
FILE_ATTRIBUTE_ROMMODULE X
FILE_ATTRIBUTE_SPARSE_FILE X
FILE_ATTRIBUTE_SYSTEM X X X
FILE_ATTRIBUTE_TEMPORARY X X X
FILE_FLAG_WRITE_THROUGH X
FILE_FLAG_RANDOM_ACCESS X
FILE_FLAG_SEQUENTIAL_SCAN X
FILE_ATTRIBUTE_ROMSTATICREF X

Table 2.18. SetFilePointer Moves the file pointer
SetFilePointer
HANDLE fileHandle Handle created by CreateFile.
LONG distance Distance to move pointer (low 32 bits).
PLONG distanceHigh Pointer to distance to move pointer (high 32 bits), or NULL.
DWORD method FILE_BEGIN move from start of file.
FILE_CURRENT move from current postion.
FILE_END move from end of file.
DWORD Return Value Returns the new location of the file pointer, or 0xFFFFFFFF on error.

Listing 2.8 Gets 5th record from file created in Listing 2.7 and displays it
 void Listing2_8() {   HANDLE hFile;   DWORD dwNumRead;   TCHAR szFilename[MAX_PATH + 1];   DATA dataRec;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   hFile = CreateFile(szFilename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout    _T("Could not open file. Error:")             GetLastError();     return;   }   SetFilePointer(hFile, 5 * sizeof(DATA), 0, FILE_BEGIN);   if(GetLastError() != NO_ERROR)   {     cout    _T("Could not seek to file. Error:")             GetLastError();   }   else   {     if(ReadFile(hFile, &dataRec,                 sizeof(DATA), &dwNumRead, 0))     {       cout    _T("Record 5: ")   dataRec.a               _T(" ")               dataRec.b   _T(" ")               dataRec.c   endl;     }     else     {       cout    _T("Could not read file. Error: ")               GetLastError();     }   }   CloseHandle(hFile); } 

File Mapping

The Win32 API provides a feature called file mapping that allows you to map a file directly into the Windows CE virtual memory space. This capability is often used to implement interprocess communication schemes and is also useful for simplifying or speeding file access.

You can map a file either for read-only or read-write access. Once mapped, you access the file by address (using array or pointer syntax) rather than using file access functions such as ReadFile or WriteFile.

For example, say that you need to access data in a file and you know that you will make a large number of writes to the file in rapid succession. Also imagine that, for performance reasons, you cannot afford the time it takes to perform all of those writes. Typically you would solve this problem by reading the file to an array, accessing the array, and then writing the array back to disk. File mapping does this automatically it maps the file into memory for you. In addition, you can share the memory image among multiple processes, and the image will remain coherent to all viewers on a single machine. If several processes all use the same file-mapping object, all changes to the mapped file will be reflected in the data read by all processes.

Listing 2.9 shows how to use file mapping in read-only mode.

Listing 2.9 Displays Unicode text file using file mapping
 void Listing2_9() {   HANDLE hFile;   TCHAR szFilename[MAX_PATH + 1];   HANDLE hFileMap;   LPTSTR lpFile;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   hFile = CreateFileForMapping(szFilename,       GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout   _T("Could not open file. Error:")            GetLastError();     return;   }   hFileMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL);   if(hFileMap == NULL)   {     cout    _T("Could not create file mapping:")             GetLastError();     CloseHandle(hFile);     return;   }   lpFile = (LPTSTR) MapViewOfFile(hFileMap,       FILE_MAP_READ, 0, 0, 0);   if(lpFile == NULL)     cout    _T("Could not create view of map:")             GetLastError();   else   {     if((DWORD)*lpFile != 0xFEFF)       cout   _T("Not a Unicode file");     else     {       lpFile++;  // skip over first two bytes.       // DANGEROUS! Assumes '\0' terminated file       cout   lpFile;     }     UnmapViewOfFile(lpFile);   }   CloseHandle(hFileMap);   CloseHandle(hFile); } 

The program in Listing 2.9 begins by asking the user for a filename and opening the file with CreateFileForMapping. In Windows CE, CreateFileForMapping should be used to open a file ready for file mapping, instead of CreateFile. As Table 2.19 shows, this function takes the same arguments as CreateFile.

Table 2.19. CreateForFileMapping Opens a file for mapping
CreateForFileMapping
LPCTSTR lpFileName File for which a mapping is to be created.
DWORD dwDesiredAccess Type of access. 0, GENERIC_READ or GENERIC_WRITE.
DWORD dwShareMode How the file can be shared. 0, FILE_SHARE_READ, FILE_SHARE_WRITE.
LPSECURITY_ATTRIBUTES lpSecurityAttributes Not supported, pass as NULL.
DWORD dwCreationDisposition How the file will be created. See CreateFile for options.
DWORD dwFlagsAndAttributes Attributes and flags for file. See CreateFile for options.
HANDLE hTemplateFile Not supported, pass as NULL.
HANDLE Return Value Handle to a file object that can be mapped, or INVALID_HANDLE_VALUE on failure.

Listing 2.9 then calls the CreateFileMapping function to create the mapping. This step determines the size of the mapping as well as its data. The protection is set to read-only, and setting sizeLow and sizeHigh to zero sets the size to the current file size.

Table 2.20. CreateFileMapping Creates and names a mapping
CreateFileMapping
HANDLE fileHandle Handle to the file, or 0xFFFFFFFF for a memory block
LPSECURITY_ATTRIBUTES security Security attributes (not supported, pass as NULL)
DWORD protect Access protection (read-only vs. read-write)
DWORD sizeHigh Maximum size of the mapping, high 32 bits
DWORD sizeLow Maximum size of the mapping, low 32 bits
LPTSTR mapName Name of the mapping
HANDLE Return Value Returns a handle to the mapping, or NULL on error

The MapViewOfFile function reserves data in an address range set aside for memory-mapped files, and returns the new address of the data. The address range for memory-mapped files is above the address range used for processes. The data from the file will be paged into this memory space as you access it. In Listing 2.9, lpFile is declared as a pointer to a character so that the data can be treated text. You can declare lpFile to be of any type. For example, if the file contains a set of structures, let lpFile be a pointer to that type of structure.

Table 2.21. MapViewOfFile Loads a file mapping into memory
MapViewOfFile
HANDLE mapHandle Handle to the mapping
DWORD access Type of access (read-only, read-write, etc.)
DWORD offsetHigh Offset into the file, high 32 bits
DWORD offsetLow Offset into the file, low 32 bits
DWORD number Number of bytes to map
LPVOID Return Value Returns the starting address of the view, or 0 on error

In Listing 2.9, the code maps the entire file with read-only access. Once mapped, lpFile points to the address of the mapping, and you use it just like any other pointer or array. If you load a text file with this program, the cout statement displays the entire file, as shown. This is dangerous, since cout will assume that whatever lpFile points at is null-character terminated, but this is not generally the case for text files. The code will work until you try to open a file that contains an exact number of memory pages. In this situation, cout will look beyond the last page for the null character, and this will often cause a page fault.

Once you have finished with the file, use UnmapViewOfFile to unload the memory and write any changes back to the original file. No changes were made here, but the next example makes use of this feature.

Table 2.22. UnmapViewOfFile Releases the view and writes changes back to the file
UnmapViewOfFile
LPVOID address Address of the mapping that was returned from MapViewOfFile
BOOL Return Value Returns TRUE on success, or FALSE on failure

Listing 2.10 shows a second example of file mapping. Here the program opens the mapped file for read-write access and then writes to the file. The changes are flushed to disk only when the program calls UnmapViewOfFile.

Listing 2.10 Displays Unicode text file using writable file mapping
 void Listing2_10() {   HANDLE hFile;   TCHAR szFilename[MAX_PATH + 1];   HANDLE hFileMap;   LPTSTR lpFile;   DWORD dwSizeLo;   if(!GetFilename(_T("Enter filename:"),       szFilename, MAX_PATH))     return;   hFile = CreateFileForMapping(szFilename,     GENERIC_READ | GENERIC_WRITE,     0, 0, OPEN_EXISTING, 0, 0);   if(hFile == INVALID_HANDLE_VALUE)   {     cout    _T("Could not open file. Error:")             GetLastError();     return;   }   // assume < 4 gigabytes   dwSizeLo = GetFileSize (hFile, NULL);    hFileMap = CreateFileMapping(hFile, 0,     PAGE_READWRITE, 0, dwSizeLo + 1, NULL);   if(hFileMap == NULL)   {     cout    _T("Could not create file mapping:")             GetLastError();     CloseHandle(hFile);     return;   }   lpFile = (LPTSTR) MapViewOfFile(hFileMap,       FILE_MAP_WRITE, 0, 0, 0);   if(lpFile == NULL)     cout    _T("Could not create view of map:")             GetLastError();   else   {     if((DWORD)*lpFile != 0xFEFF)       cout   _T("Not a Unicode file");     else     {       // add terminating NULL character       lpFile[dwSizeLo] = '\0';       // skip over first two bytes.       lpFile++;       cout   lpFile;     }     UnmapViewOfFile(lpFile);   }   CloseHandle(hFileMap);   // remove NULL character at end of file   SetFilePointer(hFile, -2, NULL, FILE_END);   SetEndOfFile(hFile);   CloseHandle(hFile); } 

Listing 2.10 opens the mapping for reading and writing. A null character is appended to the end of the file, and this makes writing the contents of the file to cout safe. The null character needs to be removed once the mapping is closed. This can be done by moving the file pointer to the byte before the null character and then calling SetEndOfFile to set the end of file to the current file position.

Table 2.23. SetEndOfFile Sets end of file to current file position
SetEndOfFile
HANDLE hFile Handle of file to set end of file for
BOOL Return Value Returns TRUE on success, or FALSE on failure

The function FlushViewOfFile can be used to write any changed data out to the Object Store. This function is also useful when using a read-only mapped file. As you read through a file, pages of memory are used to store the data. If you are reading a large file, significant amounts of the device's scarce memory can be used up. Calling FlushViewOfFile will release these pages of memory.

Table 2.24. FlushViewOfFile Flushes changes in the view to Object Store
FlushViewOfFile
LPVOID address The base address of the bytes to flush
DWORD number The number of bytes to flush
BOOL Return Value Returns TRUE on success, FALSE on failure

When using FlushViewOfFile, you generally flush the entire file. The system is smart enough to write back to disk only those memory pages that actually contain modified data.


< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net