Добрый день. Имеется консольное приложение, создаваемое через CreateProcess(CREATE_NEW_PROCESS_GROUP). Дескрипторы ввода-вывода переназначаются на анонимные пайпы. При некоторых условиях консольное приложение зацикливается и требуется послать ему Ctrl+C (оно умеет обрабатывать его). Попытка реализовать это через GenerateConsoleCtrlEvent(CTRL_C_EVENT,pInfo.dwProcessId) ни к чему не приводит: GetLastError возвращает 6 (неверный дескриптор). Как же всё-таки послать консольному приложению сигнал прерывания работы (Ctrl+C)?0
Бляха-муха! Ну совсем народ на поиск забил! Ведь пару дней назад было. http://wasm.ru/forum/index.php?action=vthread&forum=4&topic=6737
Vladimir Bondarenko А ведь действительно, так не выходит. Если, например, взять tutorial Iczelion'a ("пайпы") и добавить в него запись — не получается завершить консольное приложение таким способом. bogrus Да, и на это не реагирует. Но не само приложение (например, tracert) не реагирует на Ctrl+C/Ctrl+Break, а не реагирует на GenerateConsoleCtrlEvent. Но почему код ошибки 6? Ведь даже если в dwGroupProcessID указать 0 (отсылать всем процессам, разделяющим консоль с моим), то всё одно ошибка та же. Toxic Что-то я в том топике не нашёл решения проблемы. Может, поделишься?
sensy Надо в GenerateConsoleCtrlEvent вместо pID слать ноль, а у себя поставить handler, который будет глушить стандартный обработчик Ctrl+С дла вызывающего процесса(т.е. твоего). Не надо ля-ля... Реагирует отлично.
Toxic Код (Text): SetConsoleCtrlHandler(NULL,TRUE); .if !GenerateConsoleCtrlEvent(CTRL_C_EVENT,NULL){ DWORD r = GetLastError(); // результат 6 if!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,NULL){ r = GetLastError(); //результат 6 return NULL; } } Или я неправильно ставлю обработчик?
sensy Ох, а доки я за тебя читать буду? Т.е. ты просто глушишь Ctrl+C для себя и всех своих порождений. Надо дать в SetConsoleCtrlHandler указатель на свою процедуру обработчика, и там возвращать True по приходе Ctrl+C, тем самым блокируя передачу сигнала следующему обработчику в цепочке(который вызывает ExitProcess).
Toxic Хорошо, указал свой обработчик. Честно говоря, так сначала и собирался, но смутили слова , я подумал, что ignore Ctrl+C лучше. Но не в этом дело. Код (Text): SetConsoleCtrlHandler(&Handler,TRUE); … if !GenerateConsoleCtrlEvent(CTRL_C_EVENT,NULL){ DWORD r = GetLastError(); // результат 6 if!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,NULL){ r = GetLastError(); //результат 6 return r; } return r; } 1) Функции по прежнему возвращают код ошибки 6; 2) Управление в мой Handler так и не приходит. Можно пример кода рабочего? Или хотя бы объяснить, почему GetLastError = 6.
sensy Дык непонятно, что ты запускаешь, как запускаешь и т.д. Я по вышеприведенной методике посылаю Ctrl+C на tracert - все сразу закрывается. Показывай свои СreateProcess и пайпы(если есть). _1113902227__tracert.jpg
Toxic Есть мысль. Многопоточность влияет на енто дело? Если пайпы создавать в одном потоке, а с приложением работать в другом? Код (Text): SetConsoleCtrlHandler(&Handler,TRUE); … CreatePipe(&Pipes.hOutRead,&Pipes.hOutWrite,&SecAttrs,NULL); CreatePipe(&Pipes.hInRead,&Pipes.hInWrite,&SecAttrs,NULL); … sInfo.dwFlags = STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES; sInfo.wShowWindow = SW_HIDE; sInfo.hStdInput = Pipes.hInRead; sInfo.hStdOutput = Pipes.hOutWrite; sInfo.hStdError = Pipes.hOutWrite; CreateProcess(NULL,szCmdBuf,&SecAttrs,&SecAttrs,TRUE,NULL,NULL,NULL,&sInfo,&pInfo); … CloseHandle(Pipes.hOutWrite); CloseHandle(Pipes.hInRead); … // Break action if !GenerateConsoleCtrlEvent(CTRL_C_EVENT,NULL){ DWORD r = GetLastError(); // результат 6 if!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,NULL){ r = GetLastError(); //результат 6 return r; } return r; } И tracert всё равно продолжает работать…
Toxic То есть? Работа с консолью - это дело подопытного приложения. Я же просто переназвачаю вход/выход его себе и всё. Или нет? Нужно и себе создавать консоль? Или как?
AllocConsole CreatePipe SetStdHandle SetConsoleCtrlHandler CreateProcess GenerateConsoleCtrlEvent FreeConsole Читай MSDN:
Я вот еще забавный случай вспомнил: дали мне оффлайновый форум какого-то дельфийского сайта. Там какой-то перец написал статью как с помощью пайпов и CreateProcess запустить консольное приложение и считать оттуда данные. И потом много отзывов было(и благодарности и критика), все серьезно обсуждали недостатки метода - когда консольная программа хочет получить от запустившео какие-либо дополнительные данные, то вся система виснет. И никто не обратил внимания, что в CreateProcess в hStdInput и hStdOutput переданы концы hRead и hWrite одного пайпа!
Toxic Даже если я — GUI-приложение? В MSDN есть пример с переназначением стандартных ввода-вывода, но там оба приложения консольные…
sensy А какая тебе разница? Разве в вышеприведенном скриншоте ты увидел консоль? Там как раз GUI, а консоль спрятана, чтобы глаза не мозолила. Ты уже давно мог бы все прочитать и поэкспериментировать - в MSDN по консолям достаточно инфы.
Интересно, что после AllocConsole открывается окно консоли и его никак не закрыть, вплоть до FreeConsole. Можно, конечно, через FindWindow найти его, но заголовок окна заранее не известен (зависит от имени файла). Кто-нибудь знает, как скрыть окно консоли?
Народ, объясните плз и мне тормозу - как через GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pr.dwProcessId) закрыть cmd.exe которое запустил так: CreateProcessA( PAnsiChar('C:\Windows\System32\cmd.exe'), PAnsiChar(''), nil, nil, True, CREATE_NEW_PROCESS_GROUP, nil, PAnsiChar('C:\Windows\System32'), st, pr ) Пишет ошибку: Неверный дескриптор.