|
Broken links? Email us! |
|
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.
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. 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
.
From | To |
HANDLE | C Library handle |
HANDLE | CFile |
C Library handle | HANDLE |
C Library handle | FILE
* |
FILE * | C Library handle |
FILE * |
CStdioFile |
CFile |
HANDLE |
CStdioFile |
FILE
* |
std xxx |
HANDLE |
<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.
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> 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.
Give a FILE *
object, you can obtain the underlying C library handle
by using _fileno
<stdio.h> int _fileno(FILE * f)
<io.h> long _get_osfhandle(int filehandle)
This takes a C library file handle and returns the underlying Win32 HANDLE
.
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.
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);
The m_pStream member of CStdioFile
is the reference to the FILE
*
object that underlies it.
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.
CStdioFile file(myfile);
or
CStdioFile * file = new CStdioFile(myfile);
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.
OK, someday soon...
Likewise...
|
|