Disclaimer
I'm working on this essay. However, the information that is already here is sufficiently useful that I decided to post in, in spite of the fact that I've only covered a small part of handles. Over the next few months, I'll be enhancing it. So be patient; more is coming.
File Handles
I have a FILE *
. Or I have a CFile
or CStdioFile
. What is its handle? And what handle is it?
There are several representations of handles for files at the application level. There are the file handles delivered by the C library, there are FILE *
objects, and there are operating system file handles. They are all interchangeable, but only if you know what you are doing.
They are not necessarily interchangeable on an instant's notice, because of issues such as buffering. Thus if you reach into a FILE *
and grab the underlying operating system handle and do a WriteFile
, you will probably end up with a seriously corrupted file because there is buffered data being managed by the FILE *
object. Therefore, unless you understand what needs to be done to flush buffers and maintain consistency in the various file handle images of the file contents and position, you are going to end up in serious trouble.
More typically, you have a fresh, newly-opened handle of one type and wish to now associate it with a representation more suitable for your task. For example, the C library function fopen
does a pitiful job of handling file sharing, a concept which was nonexistent on the Unix operating system in which it was first specified. You want to use the full Win32 file sharing, but don't want to have to do raw WriteFile
operations. And maybe you can't because you are retrofitting something into an existing, possibly portable-across-operating-systems source set, and you're writing the OS-specific module. So you can get a genuine Win32 HANDLE
from CreateFile
, and you want to associate it with a FILE *
so you can now use it conveniently. Or even associate it with a C++ fstream
. Keep reading!
C library "handles" are small integers that index into a table in the C runtime library. The C library has traditionally limited the number of simultaneously open files to some very restrictive number of handles, such as 16. This is no longer true in Win32. The C library in Win32 now supports up to 2048 low-level handles. The default is to allow a maximum of 512 FILE *
objects, although you can easily change this limit up to the maximum of 2048 by calling _setmaxstdio
.
If you don't see the transformation you need in the table below, you will need to use a combination of the transformations. For example, to transform a HANDLE
to an fstream
, you need to do something like
HANDLE h = ::CreateFile(...);
fstream f;
f.attach(_open_osfhandle(h));
<io.h>
int _open_osfhandle(long oshandle, int flags)
This takes a HANDLE
value and returns a small integer that can be used to interface with the C library. The flags
value includes O_APPEND
, O_RDONLY
, and O_TEXT
. Note that this prototype assumes that a long
and a HANDLE
are the same size, and you will have to do a cast to get it past the compiler, for example
int h = _open_osfhandle((long) myhandle, 0);
It is not clear at this point to me what Microsoft will do in Win64 for this library call, because handles in Win64 (I think) will be 64 bits wide.
back to index
Given a C library file handle, you can convert it to a FILE*
by calling the function _fdopen
, passing in the C library file handle and getting in return a FILE *
.
<stdio.h><code>
int _fdopen(int filehandle, const char * mode)
where mode
is any of the mode values you can provide to fopen
, such as "r"
, "rw"
, "w"
, etc.
back to index
Give a FILE *
object, you can obtain the underlying C library handle by using _fileno
<stdio.h>
<code>int _fileno(FILE * f)
back to index
<io.h>
long _get_osfhandle(int filehandle)
This takes a C library file handle and returns the underlying Win32 HANDLE
.
back to index
Underlying a CFile
object is a system file handle. Sometimes. Maybe. In a raw CFile,
the m_hfile
member is a system file handle. However, Microsoft cautions that this may change in a derived class.
back to index
To associate a CFile
object with an operating system file handle, you use the CFile
constructor of the form
CFile::CFile(HANDLE h)
Whether you do this in a stack variable or use heap allocation depends on the nature of your application.
CFile file(myhandle);
or
CFile * file = new CFile(myhandle);
back to index
The m_pStream
member of CStdioFile
is the reference to the FILE *
object that underlies it.
back to index
To associate a CStdioFile
object with an operating system file handle, you use the CStdioFile
constructor of the form
CStdioFile::CStdioFile(FILE * f)
Whether you do this in a stack variable or use heap allocation depends on the nature of your application.
<code>CStdioFile file(myfile);
or
CStdioFile * file = new CStdioFile(myfile);
back to index
If you need a handle to stdin
, stdout
, or stderr
, without using the stdio.h library, you can use the API call GetStdHandle
, specifying one of the constants, STD_INPUT_HANDLE
, STD_OUTPUT_HANDLE
, or STD_ERROR_HANDLE
. These return a HANDLE
value which can be used for ReadFile
, WriteFile
, or with any of the above.
back to index
If you have a C Library handle (the small integer from _open
or _sopen
) and need a C++ fstream
-class object, take a look at the fstream
constructor. One form takes a C file descriptor:
fstream(filedesc fd)
You can also use the fstream::attach
method to attach a file descriptor to an existing fstream
:
fstream f;
f.attach(fd);
For this to work, there must not be a file descriptor already attached to the fstream
.
back to index
"fstream to C Library handle">fstream to C Library handle
To obtain the underlying C library handle from an fstream
, use the .fd
method
fstream f;
f.attach(fd)
ASSERT(fd == f.fd())
back to index
Inheritable handles
OK, someday soon...
Other Handles
Likewise...