Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Системное программирование и WinAPI > Замещение родительского процесса дочерним |
Автор: alexx83 20.12.2012, 21:45 | ||
Добрый день! Необходимо решить следующую задачу: Имеются 2 консольных приложения, одно и которых при запуске меняет часть переменных среды и запускает второе приложение с заданными параметрами. Второе приложение должно взаимодействовать с вводом-выводом в консоль. На данный момент это реализовано через CreateProcess, при этом второму процессу передаются хэндлы ввода-вывода и в принципе все нормально отрабатывает. Но есть одно НО. При несанкционированном завершении родительского процесса, например через диспетчер задач, дочерний процесс остается висеть в памяти. Необходимо в идеальном случае замещать родительский процесс дочерним с сохранением взаимодействия с консолью в дочернем процессе. На данном этапе набросан черновик с использованием _execvpe, при вызове которого родительский процесс замещается дочерним. Возникла проблема с вводом-выводом в консоль из дочернего процесса. При запуске дочернего процесса, он выводит некоторую информацию в консоль, но при попытке пользовательского ввода с клавиатуры возникает ошибка:
После чего дочерний процесс висит в памяти но консоль с ним уже не связана. Кто-нибудь сталкивался с подобным или знает пути решения? Заранее спасибо! |
Автор: alexx83 21.12.2012, 08:02 | ||
Через CreateProcess вызываю так:
|
Автор: alexx83 21.12.2012, 11:25 |
Можете показать реализацию _execvpe? |
Автор: feodorv 21.12.2012, 19:21 | ||||||||||
Вроде, всё на месте))) Поясните тогда, пожалуйста:
Дочерний процесс в конце концов не завершается самостоятельно, или же просто Вам хочется, чтобы он умирал синхронно со смертью родительского?
Почему тогда Почему не завершать родительский процесс сразу (ну, или после WaitForInputIdle)? Дочерний процесс теряет способность взаимодействия с консолью? Могу, но кода много и он относится к MSVS C++ 6.0. Добавлено через 1 минуту и 35 секунд Файл Execvpe.c
Добавлено через 2 минуты и 29 секунд Файл Execve.c
Добавлено через 3 минуты и 43 секунды Файл Spawnve.c
Добавлено через 6 минут и 17 секунд Остальное через 15 минут))) |
Автор: alexx83 21.12.2012, 19:45 | ||||
На работе вроде отправлял сообщение сюда что реализацию _execvpe нашел которую вы выложили. Все равно спасибо! Не нашел только реализацию функции comexecmd() - msdn ничего не нашел и в студии тоже не нашел.
Да нужно чтобы процессы умирали синхронно.
А можно по подробнее? После CreateProcess просто делать exit? |
Автор: feodorv 21.12.2012, 19:51 | ||
Файл Dospawn.c
Добавлено через 8 минут и 13 секунд Это делается через http://msdn.microsoft.com/en-us/library/windows/desktop/ms684161%28v=vs.85%29.aspx. Из main (etc) можно просто return))) Или ExitProcess. exit - это как-то для stdlib. Но я бы предварительно сделал WaitForInputIdle на всякий случай... См. вышеприведённый файл Spawnve.c ![]() |
Автор: alexx83 21.12.2012, 20:27 | ||
Если делаю так:
То получаю такой же результат как при использовании _execvpe, т.е. могу ввести только одну команду в консоли дочернему процессу и он отрубается от консоли |
Автор: alexx83 21.12.2012, 21:21 | ||||
Сделал через jobs:
Единственное если снимаю родительский процесс через менеджер процессов, то опять получаю:
Можно от этого избавиться? |
Автор: feodorv 21.12.2012, 23:15 | ||||
Даже не знаю, что сказать. Я бы ещё поэкспериментировал с флагом наследования, с GetConsoleProcessList() и т.д., но на всё это нужно время...
Опять-таки, не знаю, чем помочь... |
Автор: boostcoder 22.12.2012, 00:04 |
feodorv, здравствуй. уже и мне сабж любопытен. давай начнем сначала, а то я запутался... скажи, каким образом я могу запустить дочерний процесс так, чтоб он унаследовал дескрипторы стандартного ввода/вывода, и чтоб по завершению родительского процесса завершался дочерний? в линукс это решается банальным использованием http://linux.die.net/man/2/fork в родительском, и http://linux.die.net/man/3/execvp в дочернем. спасибо. |
Автор: boostcoder 22.12.2012, 00:21 |
но в данном случае fork() лишний, да. |
Автор: feodorv 22.12.2012, 04:54 | ||||||||||
boostcoder, здравствуй ![]() К сожалению, Windows - вещь в себе, и часто приходится искать неочевидные решения, использовать неочевидные опции (среди многочисленных подобных), чтобы добиться желаемого результата.
Это первая часть вопроса, не менее важная, чем вторая. http://msdn.microsoft.com/en-us/library/ms682528%28v=VS.85%29.aspx сказано, что если при вызове CreateProcess (для консольного экзешника) не пользоваться флагами CREATE_NEW_CONSOLE и DETACHED_PROCESS, то дочерний процесс остаётся прикреплённым к консоли родительского процесса. Правда, я лично обычно всё же выставлял bInheritHandles в TRUE, а в STARTUPINFO устанавливал стандартные хендлеры не смотря на то, что это, вроде, и не требуется:
Почему всё-таки прописываю стандартные хендлеры в STARTUPINFO, хотя эта структура должна бы иметь смысл только при создании новой консоли.
Никак. Дочерний процесс в огромной степени независим от родительского, если не объединять их в "задания". alexx83 очень хорошо реализовал эту схему, да, с неприятным сайд эффектом... Вполне возможно, что смерть родительского процесса каким-то образом сказывается на консоли (т.е. отсоединяет от неё дочерний процесс), к сожалению, опыта работы с такими ситуациями нет. В принципе, если вся проблема в переменных среды, то можно как-нибудь исхитриться запускать только дочерний процесс через батник, в котором и выставлять или менять нужные переменные окружения. А может, дело в самом экзешнике дочернего процесса, как я понял, это gdb. Возможно, это он хитро реагирует на смерть родительского процесса. Добавлено через 4 минуты и 6 секунд Имеется в виду CREATE_NEW_CONSOLE. Добавлено через 10 минут и 39 секунд Ну, в принципе, можно организовать взаимодействие через пайпы, тогда при кончине родительского процесса дочерний процесс понимает, что пайп закрылся, и можно завершаться. Но это не наш случай, у нас стандартные хендлеры не переопределяются... |
Автор: alexx83 22.12.2012, 08:57 | ||
Сделал с заполнением хэндлов
Результат такой же как и без заполнения ![]() |
Автор: boostcoder 22.12.2012, 23:27 |
как я понял, семейство функций exec*() работает не так как в POSIX, хотя именно для этого эти функции и предоставляются msvcrt.dll. |
Автор: feodorv 23.12.2012, 00:08 | ||
Многое не работает как в POSIX, а msvcrt.dll - это только лишь майкросовтовская реализация стандартной библиотеки, насколько можно приближенная к POSIX, но в общем и целом стандарту не соответствующая. Но! Майкрософт разработала специальную подсистему POSIX, в которой реализован стандарт, но в которой уже недоступны родные вызовы WinAPI. |
Автор: boostcoder 23.12.2012, 00:14 | ||
это что? |
Автор: volatile 23.12.2012, 00:23 | ||||
Два раза прочитал, так и не понял, что нужно... 1.
То есть родитель вам больше не нужен. и он может благополучно завершиться, оставив работать дочерний? 2. мысль, перпендикулярная первой ![]() Нужно чтобы висели оба, причем родитель, исключительно для того чтоы при прибивании его, прибивался и дочерний? (больше от него проку то нет, все его функции замещены дочерним.)
Сформулируйте задачу четко. Тогда может и сами решите. А пока не сформулируете чётко, ее никто не решит. (и посикс тут не причем) |
Автор: feodorv 23.12.2012, 00:38 |
Нет, нет, всё понятно. Просто пытались рассмотреть разные возможности, поэтому такие несоответствия... Но всё неудачно ![]() А если всё таки запускать gdb (или что там) через bat-файл, в котором и выставлять нужные переменные окружения? http://technet.microsoft.com/en-us/library/cc768080.aspx ![]() |
Автор: volatile 23.12.2012, 00:48 |
Ну раз все понятно, тогда видимо я недостаточно сообразителен. Посему, удаляюсь... ЗЫ: Хочу сказать только, что если первое, то делал неоднократно, и все прекрасно работало. Если второе не делал, потому как бессмысленно, но уверен что и это сделать можно. |
Автор: boostcoder 23.12.2012, 01:02 | ||||
ну... я хз что в нем хитрого..gdb как gdb.
нужно попробовать. а можно взглянуть на фрагмент кода? ибо я сам проверял, и сабж невозможен. я больше склоняюсь к тому, что в вендус, вообще невозможно заменить родительский процесс дочерним. Добавлено через 9 минут и 35 секунд я вот только не понял, начиная с какой версии вендус предоставляется это? |
Автор: volatile 23.12.2012, 01:18 | ||||
boostcoder, я щас скомпилил тот код что приведен в этой теме. в этом посте:
У меня так: Ззапускается родитель. затем он запускает дочерний. затем родитель завершается. дочерний остается с той консолью, что была у родителя и полноценно работает и на ввод и на вывод. Все пашет. А вот зачем это мне не понять... ![]() |
Автор: feodorv 23.12.2012, 01:25 | ||||
Это вряд ли ![]() Вот этого не хотелось бы... Как раз хотелось бы Вашего участия...
Так и я о том же... Что-то здесь не так ![]() Как я понимаю всё же, gdb скомпилён в GNU окружении, эмулирующем поведение UNIX. И как там сказывается эта эмуляция - я хз)))
Как раз начиная с NT, какое-то там военное ведомство отказалось сертифицировать Windows NT без надлежащей поддержки POSIX. Изначально был реализован POSIX.1, сейчас число вызовов расширено (то ли 2000, то ли 3000 штук), но всё равно работа возможна только в текстовом режиме. |
Автор: volatile 23.12.2012, 01:46 | ||||
В father.exe нажимаем 'f', запускается son.exe, father.exe завершаецца. Для выхода нажимаем точку "." father.exe
son.exe
![]() Добавлено через 1 минуту и 41 секунду езешники father.exe, son.exe положить в одну папку. |
Автор: boostcoder 23.12.2012, 01:50 | ||||||
я размышляю привычными для меня терминами. в линукс, замещение процесса означает, загрузку другого процесса в адресное пространство первого. то, что описал ты, дает почти тот же результат. (я не говорю про наследование UID и GID)
это следствие того, что невозможен сабж, и приходится искать альтернативные способы достижения цели. нет. gdb умеет работать в нативной вендус среде.
странно...впервые вообще слышу о такой штуковине. посмотрел экспорт dll`ки - да, экспортируются POSIX функции. Добавлено через 3 минуты и 44 секунды volatile, спасибо. завтра буду проверять. что-то уже и я запутался ![]() Добавлено через 7 минут и 16 секунд кто-то может подсказать, существуют ли вообще в открытом доступе исходники этой psxdll.dll? |
Автор: volatile 23.12.2012, 01:58 | ||
так... этого в теме еще не было... В таком случае это еще и 3 альтернатива, того что нужно ТС... ![]() Имхо, здесь каждый говорит о своем, потому-что
|
Автор: boostcoder 23.12.2012, 02:04 |
ладно, пусть сформулирует... |
Автор: alexx83 23.12.2012, 08:59 | ||||
Спасибо что присоединились к этой теме volatile.
Задача проста: пишется враппер к gdb. Задача враппера изменить переменные среды и запустить gdb так чтобы он оставался привязанным к консоли в которой запущен враппер. Первый вариант - при этом враппер нам больше не нужен и он должен быть уничтожен. Второй вариант (если враппер не может быть уничтожен) - при завершении враппера должен завершаться и сам gdb. Для примера, вы работаете в IDE и запускаете приложение на отладку. Вместо самого gdb сначала запускается враппер который потом запускает gdb. IDE ничего не знает о враппере. По поводу вашего примера volatile. У меня от не работает как у вас на картинке ![]()
Может это глюк винды? |
Автор: volatile 23.12.2012, 09:49 |
Естественно. Это же ваш код, взятый в этой теме. Я просто взял ваш код и показал что у меня он работает. alexx83, понятно, я попробую воссоздать баг, если удастся конечно. (я не пользуюсь gdb). По крайней мере, проблема прояснилась. |
Автор: boostcoder 23.12.2012, 09:52 |
volatile, вот как у меня работают тобою предкомпилированные екзешники:![]() Добавлено через 11 минут и 7 секунд win7, 64-bit. Добавлено через 13 минут и 24 секунды по выводу видно, что sun.exe запускается как отдельно введенная команда, а значит наследование дескрипторов не происходит. |
Автор: alexx83 23.12.2012, 10:06 |
У boostcoder точно также работает как и у меня)) Volatile если есть возможность то вы попробуйте запустить ваши экзешники на компе без VisualStudio. |
Автор: volatile 23.12.2012, 10:15 | ||
Именно так и запускал. А вот когда запускаю из под чего-то третьего "grandfather", тогда да, получается как у вас. Добавлено через 1 минуту и 23 секунды alexx83, проблема понятна. будем посмотреть... |
Автор: volatile 23.12.2012, 14:40 |
alexx83, хорошо. Ну а с Job' ами почему у вас не работает? Собрал фазера, опять с вашим-же кодом (тем где Job' ы), и опять у меня все прекрасно работает. и даже из под грандфазера, и вообще из под чего-угодно.... Картинки постить не буду, уж поверьте на слово. запускаю фазер он запускает сына. сидят вместе. из менеджера закрываю фазера. сын автоматически закрывается сам. вот фазер, сына не менял. Добавлено через 1 минуту и 54 секунды вот |
Автор: alexx83 23.12.2012, 14:43 | ||
Да с jobами работает с одним неприятным моментом - когда завершается враппер то в консоли перед смертью gdb опять высакивает ошибка
|
Автор: volatile 23.12.2012, 14:46 |
что-то интернет глючит, еще раз |
Автор: alexx83 23.12.2012, 14:51 |
Вопрос по фазеру: Почему заремили GetExitCodeProcess и "return exitCode" |
Автор: volatile 23.12.2012, 14:51 |
а что это так важно? Имхо вообще не нужно закрывать процессы из менеждера. Это же не нормально само по себе? Вы хотите чтоб прибивая грубо процесс из менеджера, он расшаркивался перед вами в любезностях ??? зачем? |
Автор: alexx83 23.12.2012, 14:54 | ||
Ну типа да должен тихо уйти с миром)) |
Автор: volatile 23.12.2012, 14:58 |
просто у меня воид функция, можете вернуть, это не принципиально |
Автор: alexx83 23.12.2012, 15:01 |
Значит пока придется использовать вариант с jobами. Большое спасибо что уделил мне время) Если вдру придет еще что-нибудь в голову обязательно запостите сюда я готов перепробовать все варианты)) |
Автор: volatile 23.12.2012, 20:26 |
alexx83, в общем ваш вопрос сводится к несколько другой теме: "Почему, при насильственном убиении процесса, он на что-то там успевает пожаловаться.." Это несколько другая тема, и упирается она в очередность прибивания системой хендлов убиваемого процесса. Воссоздать такой случай мне пока не удалось... Гадать на расстоянии трудно, тем не менее, попробуйте следующее: 1. Добавьте также текущий процесс в Job. (Фактически у вас в Job' е только дочерний). т.е: AssignProcessToJobObject (ghJob, GetCurrentProcess ()) (впрочем это врядли поможет). 2. Попробуйте во враппере, после создания дочернего, но перед WaitForSingleObject вставить отключение враппера от консоли. FreeConsole (); Возможно в таком случае убиение враппера, не будет вызывать жалобы gdb, на ошибки в stdin... |
Автор: volatile 23.12.2012, 21:07 |
можно еще добавить: CloseHandle (GetStdHandle(STD_INPUT_HANDLE)); и т.д. |
Автор: alexx83 23.12.2012, 22:16 |
Большое спасибо! Как опробую отпишусь ![]() |
Автор: alexx83 24.12.2012, 08:12 | ||
Танцев с бубнами не понадобилось. Ошибки при снятии процесса куда-то ушла) Всем спасибо за обсуждение. Считаю тему закрытой. |
Автор: volatile 24.12.2012, 11:45 |
бывает... ![]() |