4

In Windows, when creating a process with CreateProcess, one can pass true as the bInheritHandles argument.

CreateProcess( , , , , bInheritHandles, , , , )

This means that all file handles marked to be inheritable will be, indeed, inherited by the child process.

How can we control whether the underlying file handle created by C++ std::fstream class is inheritable or not?

Mercalli
  • 700
  • 6
  • 16
  • 1
    You can't. If you plan to inherit, use CreateFile(). – Michael Chourdakis Apr 04 '19 at 10:47
  • However, at least if using MSVC there is a way to first get a FILE* from a HANDLE and then bind a std::fstream to that FILE*. – SoronelHaetir Apr 04 '19 at 11:28
  • Why bother with all that. Since you have to use the API, use only the API, not both the API and std. – Michael Chourdakis Apr 04 '19 at 11:37
  • @MichaelChourdakis, `fstream` objects are much easier to use. By using operator `<<` and `>>` you have automatic parsing and stringification of variables. – Mercalli Apr 04 '19 at 11:52
  • 1
    @Mercalli all std objects are limited in their functionality when compared to API, and are useful only for basic level of processing. In a full-height project, you want more power and this means the API. Besides, you can still use the buffer-level stream functions, then write the buffer to the file using the API. – Michael Chourdakis Apr 04 '19 at 11:54

2 Answers2

3

The C runtime creates inheritable handles by default.

ofstream outFile("filename.txt") ;
CreateProcess("program.exe", ..., true, ...) ; //program.exe will inherit the above file handle

So, if you want a handle to be inherited, you don't need to do anything.

If you DO NOT want a handle to be inherited, you have to set the handle's HANDLE_FLAG_INHERIT flag yourself using WinAPI function SetHandleInformation, like this:

FILE* filePtr = fopen("filename.txt", "w") ;
SetHandleInformation( (HANDLE)_get_osfhandle(_fileno(filePtr)), HANDLE_FLAG_INHERIT, 0) ;
ofstream outFile(filePtr) ;

In the third line, above, the constructor ofstream(FILE*) is an extension to the standard that exists in Visual Studio (I don't know about other compilers).

After that constructor, filePtr is now owned by outFile, so calling outFile.close() closes filePtr as well. You can completely forget about the filePtr variable.

Documentation: fopen, _fileno, _get_osfhandle, SetHandleInformation

HrW
  • 256
  • 2
  • 5
  • 2
    Alternatively, instead of "black-listing" all handles that shall not be inherited (and possibly missing OS or library handles that are out of your control), you can white-list specifically these handles you *want* to be inherited by [passing a `PROC_THREAD_ATTRIBUTE_LIST` to `CreateProcess`](https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873). – zett42 Apr 04 '19 at 17:02
2

If you're using fopen to open the file you can specify the Windows-specific "N" mode in the fopen parameters to make the handles not inheritable.

Example:

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

int main(void) {
  FILE *fp = fopen("SomeFile.txt", "rwN");
  if (!fp) {
    return -1;
  }

  system("SomeProcess.exe");

  fclose(fp);
  return 0;
}

Sources:

https://wiki.sei.cmu.edu/confluence/display/c/WIN03-C.+Understand+HANDLE+inheritance

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=vs-2019

Pouria P
  • 565
  • 1
  • 8
  • 21