c # - процесс закрытия, запущенный мной, с дочерним процессом, запущенным запущенным процессом - PullRequest
0 голосов
/ 23 июня 2019

У меня есть консольное приложение, которое я хотел бы контролировать в своем приложении C # WinForms.

По сути, я почти все сделал, кроме закрытия запущенного мной процесса.

Когда я запускаю процесс, я уже все настроил, поэтому:

process.StartInfo.FileName = @"file.exe";
process.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
process.StartInfo.Arguments = "";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true; // important - want to grab stdout
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.StandardInput.AutoFlush = true;

стандартный вывод перенаправлен правильно.

Я готов отправлять сообщения стандартного ввода, но мой процесс не получает их или игнорирует их (пока не уверен).

Я вижу две потенциальные проблемы (помимо проблем с моим кодом, конечно;))

  1. Процесс, который я запускаю, запускает его дочерний процесс, может быть возможно, что stdin должен быть направлен на этот дочерний процесс, но он не был вызван мной напрямую.

  2. Возможно, мне придется отправить сообщение не только дочернему процессу, но и всей группе. Но process.Start вообще не работает с группами, поэтому в данный момент я не могу контролировать это.

  3. Возможно, проблема связана с CreateNoWindow, что важно для меня.

Также process.Close(); не выполняет свою работу.

process.Kill(); работает, но убивает только процесс, запущенный мной, дочерний процесс, порожденный запущенным мной процессом - остается активным.

Наконец - я могу убить все процессы, получив их ID и позвонив, чтобы убить их одного за другим, но уничтожение процессов нарушает их работу, и это проблема для меня. Я хотел бы послать им сигнал о закрытии вместо этого и в конечном итоге убить, если они не ответят.

Мои попытки были:

1

process.StandardInput.WriteLine("\x3");
process.StandardInput.Close();
process.Close();

2.

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);

FreeConsole();

if (AttachConsole((uint)process.Id))
{
    SetConsoleCtrlHandler(null, true);
    GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, (uint)Process.Id);
    FreeConsole();
    SetConsoleCtrlHandler(null, false);
}

Также я пытался сделать StandardInput.WriteLine для дочерних процессов, порожденных запущенным мной процессом, но, конечно, я получил ошибку, что не могу этого сделать, поскольку я не перенаправил стандартный ввод.

Почти у меня кончились идеи. Думал об использовании своего рода SendMessageA и попытался нажать Ctrl + C?

Я знаю, что если я начну процесс, который я пытаюсь получить - прямо из cmd.exe, Ctrl + C работает, и я могу остановить приложение.

РЕДАКТИРОВАТЬ 1

Более подробная информация.

Я подтвердил, что могу подключиться к консоли двух дочерних процессов - одного, запущенного мной, и дочернего процесса, запущенного мной.

GenerateConsoleCtrlEvent сообщает истину для них обоих, но все равно никто не закрывается сам.

С другой стороны, CTRL_BREAK_EVENT кажется принятым o_O Но мое главное окно тоже закрывается и кажется, что это событие не закрывается изящно, скорее это эквивалент уничтожения ...

РЕДАКТИРОВАТЬ 2

Кажется, что PostMessage и SendMessage также не работают, но любая помощь приветствуется.

РЕДАКТИРОВАТЬ 3

И, наконец, вывод Taskkill, который может пролить свет на ситуацию?

taskkill /PID 13384 /T
ERROR: The process with PID 5456 (child process of PID 13384) could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).
ERROR: The process with PID 14188 (child process of PID 13384) could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).
ERROR: The process with PID 13384 (child process of PID 5152) could not be terminated.
Reason: One or more child processes of this process were still running.

РЕДАКТИРОВАТЬ 4

Я установил временную переменную CreateNoWindow в false. Это дало мне возможность закрыть дочернее приложение с process.CloseMainWindow(), но по-прежнему не работает никакой другой способ (GenerateConsoleCtrlEvent, proc.StandardInput.WriteLine("\x3"), SendMessage с keybd_event, PostMessage).

Я застрял.

...