#c #winapi #fstream #child-process #filehandle
#c #winapi #fstream #дочерний процесс #Дескриптор файла
Вопрос:
В Windows при создании процесса с помощью CreateProcess
можно передать его true
в качестве bInheritHandles
аргумента.
CreateProcess( , , , , bInheritHandles, , , , )
Это означает, что все дескрипторы файлов, помеченные как наследуемые, действительно будут унаследованы дочерним процессом.
Как мы можем контролировать, является ли базовый дескриптор файла, созданный std::fstream
классом C , наследуемым или нет?
Комментарии:
1. Вы не можете. Если вы планируете наследовать, используйте CreateFile().
2. Однако, по крайней мере, при использовании MSVC есть способ сначала получить ФАЙЛ * из ДЕСКРИПТОРА, а затем привязать std::fstream к этому ФАЙЛУ *.
3. Зачем беспокоиться обо всем этом. Поскольку вам необходимо использовать API, используйте только API, а не оба API и std.
4. @MichaelChourdakis,
fstream
объекты намного проще в использовании. Используя operator<<
и>>
, вы получаете автоматический синтаксический анализ и упорядочивание переменных.5. @Mercalli все объекты std ограничены в своей функциональности по сравнению с API и полезны только для базового уровня обработки. В полноразмерном проекте требуется больше возможностей, а это означает API. Кроме того, вы все еще можете использовать потоковые функции на уровне буфера, а затем записать буфер в файл с помощью API.
Ответ №1:
Среда выполнения C создает наследуемые дескрипторы по умолчанию.
ofstream outFile("filename.txt") ;
CreateProcess("program.exe", ..., true, ...) ; //program.exe will inherit the above file handle
Итак, если вы хотите, чтобы дескриптор был унаследован, вам не нужно ничего делать.
Если вы НЕ хотите, чтобы дескриптор наследовался, вам нужно самостоятельно установить HANDLE_FLAG_INHERIT
флаг дескриптора с помощью функции WinAPI SetHandleInformation
, вот так:
FILE* filePtr = fopen("filename.txt", "w") ;
SetHandleInformation( (HANDLE)_get_osfhandle(_fileno(filePtr)), HANDLE_FLAG_INHERIT, 0) ;
ofstream outFile(filePtr) ;
В третьей строке выше конструктор ofstream(FILE*)
является расширением стандарта, существующего в Visual Studio (я не знаю о других компиляторах).
После этого конструктор filePtr
теперь принадлежит outFile
, поэтому вызов также outFile.close()
закрывается filePtr
. Вы можете полностью забыть о filePtr
переменной.
Документация: fopen, _fileno, _get_osfhandle, SetHandleInformation
Комментарии:
1. В качестве альтернативы, вместо «черного списка» всех дескрипторов, которые не должны наследоваться (и, возможно, отсутствующих дескрипторов ОС или библиотеки, которые находятся вне вашего контроля), вы можете внести в белый список конкретно те дескрипторы, которые вы хотите унаследовать, передав
PROC_THREAD_ATTRIBUTE_LIST
вCreateProcess
.
Ответ №2:
Если вы используете fopen
для открытия файла, вы можете указать "N"
режим, специфичный для Windows, в fopen
параметрах, чтобы дескрипторы не наследовались.
Пример:
#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;
}
Источники:
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