Создание процесса с cmd.exe зависает, когда программа имеет много выходных данных

#c #windows #winapi #cmd #process

#c #Windows #winapi #cmd #процесс

Вопрос:

Я использую CreateProcess для вызова cmd.exe пользовательскую команду:

 #include <Windows.h>
#include <stdio.h>

int main() {
  HANDLE stdout_w = NULL;
  HANDLE stdout_r = NULL;

  SECURITY_ATTRIBUTES sattr = { 0 };
  sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
  sattr.bInheritHandle = TRUE;

  if (!CreatePipe(amp;stdout_r, amp;stdout_w, amp;sattr, 0))
    return EXIT_FAILURE;

  SetHandleInformation(stdout_r, HANDLE_FLAG_INHERIT, 0);

  PROCESS_INFORMATION pi = { 0 };
  STARTUPINFOA si = { 0 };

  si.cb = sizeof(si);
  si.hStdError = stdout_w;
  si.hStdOutput = stdout_w;
  si.dwFlags = STARTF_USESTDHANDLES;

  char command[256];
  strcpy_s(command, _countof(command), "cmd /S /C "ag "ch""");

  if (!CreateProcessA(NULL, command, NULL, NULL, TRUE, 0, NULL, "c:/users/lisa/projects/monkey", amp;si, amp;pi))
    return EXIT_FAILURE;

  while (true) {
    switch (WaitForSingleObject(pi.hProcess, 0)) {
      case WAIT_TIMEOUT:
        break;
      case WAIT_OBJECT_0:
        return EXIT_SUCCESS;
      default:
        return EXIT_FAILURE;
    }
  }
}
  

Здесь я вызываю cmd.exe с помощью команды ag "ch" . ( ag это утилита, которая ищет в файлах строку, вроде как grep .)

Проблема в том, что она зависает — цикл в конце выполняется вечно, и я вижу, что созданный cmd.exe процесс остается открытым в диспетчере задач. Пара странных вещей об этом:

  • Когда я запускаю cmd.exe /S /C "ag "ch"" непосредственно из командной строки, он работает нормально и завершается, как ожидалось.
  • Когда я меняю код для запуска ag "chi" (т. Е. Для поиска большей подстроки), он завершается, как и ожидалось. Кроме того, когда я меняю каталог на папку без каких-либо файлов, он также завершается, как и ожидалось. Это заставляет меня думать, что проблема в том, что вывод ag слишком длинный.
  • Когда я напрямую передаю ag "ch" команду CreateProcess , она завершается, как и ожидалось. (К сожалению, я не могу этого сделать, потому что это часть более крупной утилиты, которая позволяет мне запускать любую пакетную команду из C, в том числе с использованием каналов.)

У кого-нибудь есть идеи, что здесь происходит?

Комментарии:

1. Я бы ожидал, что ваша текстовая строка команды будет "cmd /S /C ag "ch"" , а не "cmd /S /C "ag "ch""" . Мне кажется, что слишком много двойных кавычек приводит к командной строке cmd /S /C "ag "ch"" и тому, что вы хотите cmd /S /c ag "ch" .

2. почему вы запускаете cmd вместо прямого ag.exe ? где вы используете перенаправленный вывод? для чего вы его перенаправляете? вы ничего не читаете и не записываете в каналы

3. Этот код удален из более крупного служебного класса, который позволяет мне вызывать любую пакетную команду (например ag ch | filter ) и считывать выходные данные. Этот код предназначен только для демонстрации проблемы.

4. Канал заполнен, поэтому программа не может записать в него больше данных. Вы должны прочитать уже записанные данные из канала, чтобы освободить место для большего.

5. Почему вы вызываете WaitForSingleObject() в замкнутом цикле с таймаутом 0 мс? Полностью избавьтесь от такого цикла опроса и просто вызовите WaitForSingleObject() один раз с INFINITE таймаутом.