File I/O in a C++ Application on Pocket PC 2002 When your Microsoft® eMbedded Visual C++® application for the Microsoft Windows® Powered Pocket PC 2002 needs to create or access data files, you have several options. While there are other ways to do file Input/Output (I/O), most applications will use either the Microsoft Win32® application programming interface (API) functions (CreateFile, ReadFile, WriteFile), or the Microsoft Foundation Classes (MFC) class CFile and its methods. What You Need Microsoft eMbedded Visual Tools 3.0. Gotchas File names on Pocket PC 2002 are a bit tricky at first, so a section on them has been included in this article. Languages Supported English. Pocket PC 2002 File Names The Pocket PC 2002 file system does not use drive letters, all fully qualified file names (file names that include the full directory path to the file) start with the backslash character, which means “the root of the device” not “the root of main storage memory” as some people believe. CompactFlash™ (CF), Multimedia Cards, and PC cards are all considered storage cards by Pocket PC 2002, and are named as such, with the first card being named “Storage Card” and subsequent cards being named “Storage Card2”, “Storage Card3”, and so on. So to access a file in the Pictures directory on a CF card, your file name might be \Storage Card\Pictures\MyFile.jpg. Directories in main memory are taken directly off the root, so \Windows\MyCustom.DLL would also be valid. Other valid file names are COM1: to use direct serial-port access (depending on your device type, of course) and COM3: to use the infrared port. File I/O Using the Win32 API Functions The Win32 API is robust and versatile, so versatile in fact that it can be a little overwhelming when you first look at the documentation, because it is used for many types of I/O, not just data files as its name would imply. Although the parameters can be varied depending on your application’s needs, many times they are usually the same for most applications. Create or open the file by using the CreateFile() function. This same function is used for either operation, and it can be directed to overwrite an existing file, fail if a file exists, and many other options too numerous to list here. For the dwDesiredAccess parameter, specify GENERIC_READ or GENERIC_WRITE or both (using the OR operator, that is, GENERIC_READ | GENERIC_WRITE). For the dwShareMode parameter, specify FILE_SHARE_READ, which will allow other applications to read your file without locking it so that you can’t write to it (this allows the file to be copied without having to close your application). Set the security attributes to NULL, which is currently the only supported value. On a read-only file, set dwCreationDisposition to OPEN_EXISTING, this will fail if the file does not exist. At all other times, you will want to set dwCreationDisposition to OPEN_ALWAYS, which creates the file if it doesn’t exist, but opens it if it does. Set the attribute to FILE_ATTRIBUTE_NORMAL. Set hTemplateFile to 0, because it’s ignored anyway. If CreateFile() successfully opens your file, you will receive a handle to the file. If it fails, it will return INVALID_HANDLE_VALUE, and you can call GetLastError() to determine why the file could not be opened or created. Once you have the file handle, you can move through the file with the SetFilePointer() function. You can use this function to move to a position relative to the beginning or the end of the file, or from the current position (see the following Figure). When you have positioned the file pointer where you want it, you can write to the file with the WriteFile() function or read from the file with the ReadFile() function (passing NULL for the lpOverlapped parameter, as overlapped I/O is an article in itself). When you are finished with the file, you should always call the CloseHandle() function. File pointers in Win32 and MFC. File I/O Using the MFC CFile Class Microsoft has encapsulated the Win32 file I/O functions in a class they named CFile. While the CFile class has nearly identical functionality to the Win32 functions it wraps, there are several good reasons to use it if you are already using MFC in your application: It can be used as a base class for a custom file I/O class. Because the Win32 file handles are closed in the class destructor, there is less chance for a resource leak in your application (true for any type of handle-wrapper class, by the way). Readability of the source code is a little better. There is less chance of passing the wrong handle to a function call, because it would be caught at compile time as a syntax error, instead of needing to wait until run time. Again, the parameters might vary with your application’s needs, but in general, these will work for your application every time: Construct the CFile object without passing the file name. Because constructors do not return values to indicate success or failure, and eMbedded Visual C++ does not currently support exceptions, there is not a good way to check for failure if the file cannot be opened when you try to do it in the object constructor. Call the CFile::Open() method to open the file. As with the Win32 CreateFile() function, this method can also be used to open an existing file or create a new file. For the nOpenFlags parameter, you will generally specify one of the following: either CFile::modeReadWrite | CFile::shareDenyWrite if you are going to read and write the file, or simply CFile::modeRead if you are only going to read the file. For the pError parameter, pass a pointer to a CFileException object (generally just a stack variable declared immediately before the call to the Open() method). Despite its name, this will not actually cause an exception to be thrown if the Open() method fails, but it will describe why it failed in the m_cause data member of the CFileException object. Use the Seek() method to move the pointer through the file. You can seek from the beginning, current position, or end of the file by using CFile::begin, CFile::current, and CFile::end for the nFrom parameter. Once you have positioned your file pointer, you can use the Read () and Write () methods of the CFile class to access the contents of the file. There is generally no need to close the file explicitly when using CFile, because this will happen automatically when the object is deleted. There is a Close() method you can use, though, should you want to close the file while the object is still in scope. Conclusion If you are a desktop Windows developer, you are probably surprised at how well Microsoft has shielded Pocket PC 2002 developers from the fact that there really is no disk on the Pocket PC 2002 (generally speaking). The file I/O available to developers is simple, robust, and complete. When done with a little care, this can be one of the easier parts of your application to finish. Built on Friday, December 21, 2001