Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Handy Guide To Handling Handles

0.00/5 (No votes)
24 Oct 2001 1  
The secrets of File Handles and their relationship to File *, CFile, CStdioFile, etc.

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));

Summary of Direct File Handle Transformations

From Source To use
HANDLE Win32

CreateFile

C Library handle _open_osfhandle
"#HANDLE to CFile">CFile CFile::CFile
C Library handle <io.h>

_open
_sopen

"#C Library handle to Win32 Handle">HANDLE _get_osfhandle
"#C Library handle to FILE *">FILE * _fdopen
"#HANDLE to fstream">fstream fstream::fstream or
fstream::attach
FILE * <stdio.h>

fopen

C Library handle _fileno
"#FILE * to CStdioFile">CStdioFile CStdioFile::CStdioFile
CFile MFC "#CFile to HANDLE">HANDLE m_hFile data member
CStdioFile MFC "#CStdioFile to FILE *">FILE * m_pStream data member
stdxxx Win32 "#stdxxx to HANDLE">HANDLE GetStdHandle
fstream C++ Library C Library handle .fd method of fstream


Win32 HANDLE to C Library 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.

back to index


C Library handle to FILE *

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


FILE * to C Library handle

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


C Library handle to Win32 Handle

<io.h>
long _get_osfhandle(int filehandle)

This takes a C library file handle and returns the underlying Win32 HANDLE.

back to index


CFile to 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. 

back to index


HANDLE to CFile

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


CStdioFile to FILE *

The m_pStream member of CStdioFile is the reference to the FILE * object that underlies it.

back to index


FILE * to CStdioFile

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


stdxxx to HANDLE

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


C Library handle to fstream

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...

Send mail to newcomer@flounder.com with questions or comments about this article.
Copyright � 1999 [] All Rights Reserved
www.flounder.com/mvp_tips.htm

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here