Запустить произвольные подпроцессы в Windows и все равно завершить работу? - PullRequest
14 голосов
/ 21 сентября 2009

У меня есть приложение A, которое я хотел бы иметь возможность вызывать произвольные другие процессы, указанные пользователем в файле конфигурации.

Пакетный скрипт B - это один из таких процессов, который пользователь хотел бы вызвать A. B устанавливает некоторые переменные окружения, показывает некоторые сообщения и вызывает компилятор C для выполнения некоторой работы.

Предоставляет ли Windows стандартный способ чистого завершения произвольных процессов? Предположим, что A запускается в консоли и получает CTRL + C. Это может передать это B и C? Предположим, что A запускается в окне, и пользователь пытается закрыть окно, может ли оно отменить B и C?

TerminateProcess - вариант, но не очень хороший. Если A использует TerminateProcess на B, C продолжает работать. Это может вызвать неприятные проблемы, если C долго работает, так как мы можем запустить другой экземпляр C для работы с теми же файлами, пока первый экземпляр C все еще тайно работает. Кроме того, TerminateProcess не приводит к чистому выходу.

GenerateConsoleCtrlEvent звучит неплохо и может работать, когда все работает в консоли, но в документации сказано, что вы можете отправлять только CTRL + C на свою собственную консоль, и поэтому не помогло бы, если бы А работал в окне.

Есть ли в Windows эквивалент SIGINT? Я хотел бы найти статью, подобную этой: http://www.cons.org/cracauer/sigint.html для Windows.

Ответы [ 2 ]

9 голосов
/ 12 марта 2010

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

Моя проблема похожа в том, что я хотел бы, чтобы мое приложение было приложением с графическим интерфейсом, но выполняемые процессы должны запускаться в фоновом режиме без какого-либо окна интерактивной консоли.

Мне удалось решить эту проблему с помощью GenerateConsoleCtrlEvent (). Сложность в том, что в документации не совсем ясно, как именно это можно использовать и какие подводные камни с этим связаны.

Мое решение основано на том, что описано здесь . Но это на самом деле не объясняло все детали, так что вот подробности о том, как заставить его работать.

  1. Создайте новое вспомогательное приложение "Helper.exe". Это приложение будет находиться между вашим приложением (родительским) и дочерним процессом, который вы хотите закрыть. Это также создаст фактический дочерний процесс. У вас должен быть этот процесс "среднего человека", иначе GenerateConsoleCtrlEvent () завершится неудачей.

  2. Используйте какой-нибудь механизм IPC для связи от родительского процесса к вспомогательному процессу о том, что помощник должен закрыть дочерний процесс. Когда помощник получает это событие, он вызывает «GenerateConsoleCtrlEvent (CTRL_BREAK, 0)», который закрывает себя и дочерний процесс. Я сам использовал для этого объект события, который родитель завершает, когда хочет отменить дочерний процесс.

Чтобы создать свой Helper.exe, создайте его с помощью CREATE_NO_WINDOW и CREATE_NEW_PROCESS_GROUP. А при создании дочернего процесса создайте его без флагов (0), что означает, что он получит консоль от своего родителя. Невыполнение этого условия приведет к игнорированию события.

Очень важно, чтобы каждый шаг выполнялся следующим образом. Я пробовал разные комбинации, но эта комбинация единственная, которая работает. Вы не можете отправить событие CTRL_C. Это вернет успех, но будет проигнорировано процессом. CTRL_BREAK - единственный, который работает. Не имеет большого значения, так как они оба в конце вызовут ExitProcess ().

Вы также не можете вызвать GenerateConsoleCtrlEvent () с групповым идентификатором процесса с идентификатором дочернего процесса, который напрямую позволяет вспомогательному процессу продолжать работу. Это также не удастся.

Я провел целый день, пытаясь заставить это работать. Это решение работает для меня, но если у кого-то есть что-то еще, пожалуйста, сделайте. Я ходил по всем сетям, находя множество людей с похожими проблемами, но без определенного решения проблемы. Принцип работы GenerateConsoleCtrlEvent () также немного странный, поэтому, если кто-то знает о нем больше подробностей, поделитесь.

8 голосов
/ 15 октября 2012

Как сказал @Shakta GenerateConsoleCtrlEvent() очень сложно, но вы можете отправить Ctrl + C без вспомогательного процесса.

void SendControlC(int pid)
{
    AttachConsole(pid); // attach to process console
    SetConsoleCtrlHandler(NULL, TRUE); // disable Control+C handling for our app
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // generate Control+C event
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...