В Windows, как можно создать дочерний процесс и захватить его stdin, stdout и stderr, не дублируя никаких наследуемых дескрипторов? - PullRequest
4 голосов
/ 21 октября 2009

В этой проблеме есть как минимум три части, так что потерпите меня:

1) CreateProcess имеет параметр bInheritHandles, который заставляет дочерний процесс наследовать все наследуемые дескрипторы в родительском процессе. Для этого параметра должно быть задано значение TRUE, чтобы родительский элемент мог указывать дескрипторы stdin, stdout и stderr для дочернего элемента в параметре STARTUPINFO.

2) В Win32 удаление и переименование файлов может завершиться ошибкой, если для одного и того же файла открыто более одного дескриптора.

3) Функция open () Microsoft CRT по умолчанию создает наследуемые дескрипторы. Кроме того, описатели файлов, созданные по умолчанию, страдают от проблемы 2 выше.

Эта волшебная комбинация создает следующую операционную проблему: Библиотека A вызывает open () и не ожидает последующих переименований и удалений. В другом месте процесса другая библиотека B вызывает CreateProcess с bInheritHandles, установленным в TRUE (для захвата stdin / out / err), временно создавая дубликаты дескрипторов. Теперь время от времени файловые операции библиотеки A не выполняются. Естественно, библиотеки A и B содержатся отдельными людьми. Я также знаю о другой библиотеке A ', которая использует open () и страдает от аналогичной проблемы.

В этой статье kb обсуждается связанная проблема и решение. Однако он все еще основывается на вызове CreateProcess с bInheritHandles, для которого в родительском процессе установлено значение TRUE, поэтому эта проблема не решается.

Мне интересно, сталкивались ли другие с этой проблемой и нет ли известного решения?

В статье kb, приведенной выше, по существу подразумевается, что вызов CreateProcess с bInheritHandles, установленным в значение ИСТИНА, является грубым, поэтому я склонен исправить библиотеку B так, чтобы она никогда этого не делала. Я бы сделал это:

  1. Создать приостановленный промежуточный процесс (в идеале, используя rundll для запуска пользовательской точки входа в библиотеке B) с bInheritHandles, установленным в FALSE.
  2. Создайте трубы stdin / out / err и добавьте правильные концы к промежуточному процессу.
  3. Передайте дублированные дескрипторы промежуточному процессу.
  4. Возобновите промежуточный процесс.
  5. Из промежуточного процесса заполните STARTUPINFO трубами от родителя и вызовите CreateProcess с bInheritHandles, установленным в TRUE.

Это хорошая стратегия или есть какое-то лучшее решение? Как бы вы порекомендовали передать дублированные маркеры промежуточному процессу на шаге 3? Является ли пользовательская точка входа rundll + надежным способом настройки промежуточного процесса на шаге 1?

Ответы [ 3 ]

1 голос
/ 28 января 2015

Вы можете использовать расширенный атрибут PROC_THREAD_ATTRIBUTE_HANDLE_LIST, чтобы явно указать, какие именно обработчики наследует конкретный процесс.

Публикация в блоге Раймонда Чена "Программный контроль того, какие дескрипторы наследуются новыми процессами в Win32" включает пример кода для этого.

Краткая версия:

  • InitializeProcThreadAttributeList () для создания списка атрибутов

  • UpdateProcThreadAttribute для указания дескрипторов для наследования

  • lpAttributeList член установлен в STARTUPINFOEX

  • EXTENDED_STARTUPINFO_PRESENT флаг, установленный при вызове CreateProcess

Требуется Windows Vista, поэтому, возможно, проблема с OP не была решена, когда этот вопрос был задан изначально, но сейчас все используют Vista или более поздние версии, верно? : -)

1 голос
/ 24 октября 2009

Если у вас есть доступ к фактическим дескрипторам файла, вы можете использовать SetHandleInformation (), чтобы удалить флаг HANDLE_FLAG_INHERIT перед вызовом CreateProcess ().

0 голосов
/ 26 октября 2009

Вы можете использовать функцию ZwQuerySystemInformation (SystemHandleInformation, ...) ntdll.dll, чтобы найти все дескрипторы, принадлежащие вашему процессу, а затем все SetHandleInformation на каждом из них, как предложил Реми, для удаления флага HANDLE_FLAG_INHERIT.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...