Accessing Open File Handles in a Child Process

Last reviewed: July 22, 1997
Article ID: Q104652
6.00 6.00a 6.00ax 7.00 | 1.00 1.50 1.51
MS-DOS                 | WINDOWS
kbprg kbcode

The information in this article applies to:

  • The C Run-time (CRT), included with:

        - Microsoft C for MS-DOS, versions 6.0, 6.0a, and 6.0ax
        - Microsoft C/C++ for MS-DOS, version 7.0
        - Microsoft Visual C++ for Windows, versions 1.0, 1.5, and 1.51
    

SUMMARY

To access the open file handles of a parent process under MS-DOS/Windows, it is not necessary to pass the handles of files opened in a parent process via the command line to a spawned child process. Those file handles are automatically inherited by the child process.

MORE INFORMATION

The following information describes how the handles of files opened within a parent process are inherited by the child process, and how they can be reused in the child process.

The child process will automatically inherit the file handles (type int) of all files opened in the parent process with no regard to the _fileinfo variable. This happens during the program startup, where a new PSP is set up for the child process.

A common misconception is that _fileinfo causes file handles to be passed to the child process. However, the variable _fileinfo only causes the mode flags to be passed to the child and does not affect the passing of the file handles themselves.

Setting the variable _fileinfo to a nonzero value causes the parent program to copy the mode flags for all open files into the environment variable "_C_FILE_INFO" (versions 5.1 and earlier of the Microsoft C compiler use ";C_FILE_INFO"). Each mode flag is stored in a coded form in this environment variable.

If the child process was written with Microsoft C, the startup code will check for a set _C_FILE_INFO environment string and decode it. The result is stored in the public array _osfile[]. After _C_FILE_INFO has been read, decoded, and transferred into _osfile[], it is deleted from the environment, thus making it invisible to the "main" code of the child. The values stored in _osfile[] can subsequently be used to reopen the inherited files for buffered I/O using _fdopen().

If the spawned process is a non-Microsoft C application, there is no startup code; thus, the environment string is never read, and remains visible in the MS-DOS environment. The environment string may appear to be incorrect because the mode flags encoded in _C_FILE_INFO will cause the contents of that string to look "damaged." However, this is OK because the contents are encoded.

To access files inside the child process you can do one of the following:

  • Use the low-level I/O functions.

    If this is done, all the information provided via _fileinfo, _C_FILE_INFO, and _osfile[] is not necessary because the file handles associated with the appropriate files already "know" the appropriate open mode. With this method, the child process still needs to determine what file handles are used. Some ways to do this are to access this information from osfile[] or to pass a list in via command line arguments.

    -or-

  • Use the buffered high-level I/O functions.

    If this is done, you need to reopen the files using the _fdopen() function. However, _fdopen() requires a mode flag string as second parameter. Use the values stored in the global array _osfile[], create an appropriate mode string, and reopen the file using _fdopen(). The following sample illustrates this method:

Sample Code

Parent Process

/* Compile Options Needed: None
*/

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

void main( void )
{
     unsigned int  iFileHandle1,
                iFileHandle2;

     FILE*           FPtr1,
         *           FPtr2;

     static char String [ 80 ];
     static char CmdName[    ] =   "CHILD.EXE";
     static char * ArgV [  2 ] = { "CHILD",
                           NULL
                        };

     // Open temporary files - handles will be stored in PSP.

     system("cls");
     printf("Parent: opening files \"TEST1.DAT\" and
          \"TEST2.DAT\"\n");
     FPtr1 = fopen( "test1.dat", "w+");     //,  _SH_DENYNO );
     FPtr2 = fopen( "test2.dat", "wb+");    //, _SH_DENYNO );

     // Set the _fileinfo variable that is declared in STDLIB.H to
     // force the MS-DOS environment variable _C_FILE_INFO to be
     // passed to the spawned process.
     // _C_FILE_INFO contains a char string with encoded
     // information about the modes of the open files passed to the
     // child process. The C startup code of the child will read
     // and decode _C_FILE_INFO, store the appropriate info into a
     // global array named _osfile[], and then delete the
     // _C_FILE_INFO entry from the child's environment.

     _fileinfo = 1;

     // Spawn a child process that will write a string to the file.

     printf("Parent: transferring control to child process..\n\n");
     spawnv( P_WAIT, CmdName, ArgV );

     // Rewind the files to read from the start.

     rewind( FPtr1 );
     rewind( FPtr2 );

     // Output the strings written to the files by the child.

     printf("Parent: scanning the strings from the files...\n");
     fscanf(FPtr1, "%[^\n]", String );
     printf("Parent: contents of \"TEST1.DAT\" are: %s\n", String);
     fscanf(FPtr2, "%[^\n]", String );
     printf("Parent: contents of \"TEST2.DAT\" are: %s\n", String);

     // Close the files,

     fclose( FPtr1 );
     fclose( FPtr2 );

     // and delete them.

     remove( "test1.dat" );
     remove( "test2.dat" );
}

Child Process

/* Compile Options Needed: none
*/

#include <stdio.h>
#include <string.h>

#define FOPEN      0x01  /* File handle open */
#define FRDONLY  0x10  /* File handle associated with read-only file*/
#define FAPPEND  0x20  /* File handle opened O_APPEND */
#define FTEXT      0x80  /* File handle is in text mode */

extern char near _osfile[];

void main( void )
{
    unsigned int    iFileHandle,
              iCount,
              iScanRetVal;

    static char     szFileString[] = "This is file #";
    static char     szMode[5];
    static char*    pszMode        = szMode;

    FILE*         ChildFPtr[ 255 ];

    // Use the low-level I/O file handles of the inherited files
    // and check their mode flag as stored in _osfile[]
    // to ensure reopening with the correct mode flag set.
    // Start with file #5, because the first 5 files (0-4)
    // are used for the standard I/O (stdin, stdout, stderr,
    // stdaux, and stdprn).

    for( iCount = 5 ; _osfile[ iCount ] != 0;
                iCount++, pszMode = &szMode[0] ) {

     // Set current file handle to iCount.
     // All files opened in the parent process will be open
     // in the child too, regardless of passing _C_FILE_INFO
     // or not.

     iFileHandle = iCount;

     // _C_FILE_INFO will cause _osfile[] to contain the
     // correct open modes for the inherited files, thus
     // allowing the user to reopen them for buffered I/O
     // by calling _fdopen() with the correct mode flag set.
     // To do so we must construct a mode parameter according
     // to _osfile[]:

     if(_osfile[ iCount ] & FRDONLY )
         pszMode = ( char * ) strcpy( szMode, "r");
     else
         pszMode = ( char * ) strcpy( szMode, "w+");

     if( _osfile[ iCount ] & FAPPEND )
         pszMode = ( char * ) strcat( szMode, "a");

     if( !(_osfile[ iCount ] & FTEXT) )
         pszMode = ( char * ) strcat( szMode, "b");

     // Now open the files for buffered I/O and
     // don't forget to reset pszMode for next loop.

     printf("Child: _osfile[ %i ] = %s %s %s\n",
          iCount,
          (_osfile[ iCount ] & FRDONLY) ? "_O_RDONLY" : "_O_RDWR",
          (_osfile[ iCount ] & FAPPEND) ? "| _O_APPEND" : "",
          (_osfile[ iCount ] & FTEXT) ? "| _O_TEXT" : "| _O_BINARY"
     );
     printf("Child: Now opening file using _fdopen( %d, %s )\n",
          iCount, szMode );
     ChildFPtr[ iCount ] = _fdopen( iFileHandle, szMode );
     strcpy( szMode, "\0");

     // Write some strings to the file.

     printf("Child: Now writing the string \"%s%d\" to file #%d\n",
          szFileString, iCount, iCount);

     if( fprintf( ChildFPtr[ iCount ], "%s%d\n",
          szFileString, iCount) < 0 ) {
         printf("Child: Error writing to file %d - exiting!\n",
              iCount );
         return;
     }

     // Make sure nothing remains in the buffers,
     _flushall();

     // and check the file length.
     printf("Child: Length of file is %ld bytes\n\n", _filelength(
iFileHandle ));

    }
}


Additional reference words: kbinf 1.00 1.50 6.00 6.00a 6.00ax 7.00 modeflag
KBCategory: kbrg kbcode
KBSubcategory: CRTIss
Keywords : kb16bitonly


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 22, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.