2009-09-21 2 views
14

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

Batch script 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 только на свою консоль, и поэтому не помогло бы, если бы A было запущено в окне.

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

+1

+1 для хорошего вопроса. Забавно, что ответов не было ... Я не знаю сигнального механизма в Win32. Когда мне нужно было уведомлять дочерние процессы, я отправил сообщение WM_CLOSE в приложения с графическим интерфейсом. Для консольных приложений я создал их, добавляя потоки ввода и вывода в основное приложение, и когда я хотел их закончить, я просто закрыл входной поток. Что касается детей детей и т. Д., Я полагался на своих прямых детей, чтобы очистить их зависимости :). –

ответ

9

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

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

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

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

  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() с id группы процессов id дочернего процесса, что позволяет процессу поддержки продолжать жить. Это тоже не удастся.

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

+3

Обратите внимание, что нет гарантии, что процессы B или C автоматически выйдут при получении Ctrl + C. –

+0

Хотя нет никакой гарантии, что приложение abritrary будет реагировать на Ctrl + C, если ему дано указание, что целевое приложение на самом деле известно, что оно прекратилось в ответ на ctrl + c, тогда важно знать об этом методе, что может вызвать любое такое известное приложение прекращается. – Triynko

+0

Принятый ответ должен быть от @KindDragon –

8

Как @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 
} 
+0

Было очень полезно! Лишь одна вещь отсутствует - вам нужно позвонить FreeConsole, прежде чем использовать AttachConsole, иначе вы получите ERROR_ACCESS_DENIED (5), поскольку вызывающий процесс уже подключен к консоли. – Yael

+0

Это единственный ответ на десяток вопросов, для которых у меня был ЛЮБОЙ успех, спасибо! –

Смежные вопросы