Windows includes a function to open a file and return an MS-DOS file handle:
hFile = OpenFile (lpszFileName, &of, wFunction) ;
The OpenFile funtion call returns a -1 if an error is encountered. For most uses of OpenFile, a return value other than -1 will be an MS-DOS file handle that you can use to read from and write to the file.
The lpszFileName parameter is a long (or far) pointer to the filename. A disk drive and subdirectory are optional. The wFunction parameter tells Windows what to do with this file (open it, create it, delete it, and so forth). I'll describe this parameter in more detail shortly.
The &of parameter is a far pointer to a structure of type OFSTRUCT (”open file structure“). You don't need to set any of the fields of this structure before calling OpenFile: They are filled in by the first OpenFile function call you make and are then used in subsequent OpenFile calls for the same file. The OFSTRUCT fields are shown below:
Field | Data Type | Description |
cBytes | BYTE | Length of structure in bytes |
fFixedDisk | BYTE | Nonzero for fixed-disk file |
nErrCode | WORD | MS-DOS error code |
reserved[4] | BYTE | File date and time |
szPathName[128] | BYTE | Fully qualified pathname and filename |
If the OpenFile call is successful, the szPathName field is filled with the fully qualified filename, including the current disk drive and subdirectory path. Under current versions of MS-DOS, the 128 characters allowed for this name are about 40 more than needed. A fully qualified filename has 2 bytes for the drive letter and colon, up to 64 bytes for the directory path starting with the initial backslash, another byte for the backslash following the path, up to 12 bytes for the filename (8-character name, period, and 3-character extension), and a terminating 0.
The OpenFile function has three advantages over opening a file by other means:
The lpszFileName parameter is assumed to contain characters from the ANSI character set. OpenFile does an AnsiToOem conversion on the name before trying to open the file. You would have to convert the filename yourself if you opened the file by other means.
If the file is not found in the current directory, OpenFile searches for the file on all directories listed in the MS-DOS environment PATH string.
Windows determines the fully qualified filename and inserts it in the szPathName field of the structure.
This last item is the most important feature of OpenFile. Generally, the lpszFileName parameter you pass to OpenFile when first opening or creating a file is only a filename. When you use OpenFile subsequently to open the same file, Windows uses the fully qualified szPathName field of the OFSTRUCT structure.
Here's why that's important: Although each program instance in Windows has a current disk drive and subdirectory associated with it, the DlgDirList function (which we'll use later in this chapter) can change the current drive and subdirectory associated with a program instance. Let's say you use some means other than OpenFile to obtain a filename (without a drive or directory path) located in the current directory and that you successfully open and close the file. The user then uses the dialog box to get a new file. In the process, the dialog box calls DlgDirList to change the current drive or subdirectory. The user then cancels the dialog box, and your program tries to open the original file again. It's gone! Well, it's not gone, but the current drive or subdirectory is different, so your program can't find the file. You avoid this problem by using OpenFile.
The wFunction parameter of the OpenFile call comprises one or more flags joined by the C bitwise OR operator. First, you use one of the following four flags to open an existing file or create a new file:
OF_READ | Opens an existing file for reading only |
OF_WRITE | Opens an existing file for writing only |
OF_READWRITE | Opens an existing file for reading and writing |
OF_CREATE | Creates a new file, or opens an existing file and truncates the size of the file to 0 |
Following the OpenFile call, the file is open and ready for reading and writing. The value returned from OpenFile is the MS-DOS file handle (unless this value is -1, in which case the file could not be opened or created).
If you prefer that the file be closed following the OpenFile call, you can add the flag OF_EXIST. This flag is generally used with OF_READ, OF_WRITE, or OF_READWRITE to see if the specified file exists. You can also use this flag with OF_CREATE to create the file and immediately close it. The file can be reopened later. When you use OF_EXIST, the value returned from OpenFile is -1 if the file does not exist or (with OF_CREATE) if the file could not be created. Any file handle returned from OpenFile with an OF_EXIST flag should be ignored, because the file has been closed.
With OF_READ, OF_WRITE, or OF_READWRITE, you can also use the flag OF_PROMPT. If Windows can't find the file in the current directory or in one of the directories in the MS-DOS environment PATH string, this flag causes Windows to display the infamous ”Insert [filename] disk in drive A:“ message box. Windows users appreciate this message box about as much as MS-DOS users like the ”Abort, Retry, Ignore“ message, so use this flag with discretion. Also keep in mind that the OF_PROMPT message box has only an OK button, which means that fixed-disk users must scrounge up a disk to put in drive A before proceeding. If you must use the OF_PROMPT flag, also use the OF_CANCEL flag, which adds a Cancel button to the message box. If the user selects Cancel, the OpenFile function returns -1.
That's it for the flags to open a file for the first time. The file is open when the OpenFile function returns, unless you've included the OF_EXIST flag (in which case the file has been closed) or OpenFile returns -1 (in which case an error occurred). You can now read from or write to this file and then close it. How you perform these actions is discussed in the next section.
When you want to reopen the file, you use the OF_READ, OF_WRITE, OF_READWRITE, or OF_CREATE flag in combination with the OF_REOPEN flag. The OF_REOPEN flag causes Windows to use the szPathName field in the OFSTRUCT structure to obtain the original disk drive, subdirectory, and filename of the file. Even if the current drive or subdirectory has changed since the file was first opened, this flag ensures that Windows will use the same drive and subdirectory as in the first OpenFile call. If you use OF_REOPEN with OF_CREATE, the size of the file will be truncated to 0.
When you use the OF_READ flag to open a file for reading only, you can also use the OF_VERIFY flag. This flag causes Windows to use the reserved field in the OFSTRUCT structure to verify that the date and time of the file being reopened are the same as those stored during the original OpenFile call. This works only for files opened with OF_READ, because the value for the file date and time is updated when a write-only or read-write file is closed.
Also available are two OpenFile flags that do not open files. The OF_DELETE flag deletes a file. If the file cannot be found in the current subdirectory, OpenFile uses the MS-DOS environment PATH string to search for a file to delete. Perhaps you're feeling cruel, in which case you can use the OF_PROMPT flag with OF_DELETE so that Windows also gets the chance to delete the file on the disk in drive A. OpenFile returns -1 if no file was deleted. If the file has previously been opened with OpenFile and then closed, you can use OF_DELETE in combination with OF_REOPEN.
The OF_PARSE flag does not open a file or even check for a file's existence. This flag is used by itself to parse the filename and fill in the szPathName field of the OFSTRUCT structure. OpenFile returns -1 if the filename is invalid—say, if it uses illegal characters.