Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Замещение родительского процесса дочерним 
V
    Опции темы
alexx83
Дата 20.12.2012, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



Добрый день!
Необходимо решить следующую задачу:
 Имеются 2 консольных приложения, одно и которых при запуске меняет часть переменных среды и запускает второе приложение с заданными параметрами. Второе приложение должно взаимодействовать с вводом-выводом в консоль. На данный момент это реализовано через CreateProcess, при этом второму процессу передаются хэндлы ввода-вывода и в принципе все нормально отрабатывает. Но есть одно НО. При несанкционированном завершении родительского процесса, например через диспетчер задач, дочерний процесс остается висеть в памяти. 
  Необходимо в идеальном случае замещать родительский процесс дочерним с сохранением взаимодействия с консолью в дочернем процессе. На данном этапе набросан черновик с использованием _execvpe, при вызове которого родительский процесс замещается дочерним. Возникла проблема с вводом-выводом в консоль из дочернего процесса. При запуске дочернего процесса, он выводит некоторую информацию в консоль, но при попытке пользовательского ввода с клавиатуры возникает ошибка:
Код

Exception condition detected on fd 0
error detected on stdin

После чего дочерний процесс висит в памяти но консоль с ним уже не связана.
Кто-нибудь сталкивался с подобным или знает пути решения?
Заранее спасибо!
PM MAIL   Вверх
feodorv
Дата 20.12.2012, 22:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Непонятно. 
Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
На данный момент это реализовано через CreateProcess

Не могли бы Вы дать параметры этого вызова.


Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
запускает второе приложение с заданными параметрами
 
Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
Необходимо в идеальном случае замещать родительский процесс дочерним
 
Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
При несанкционированном завершении родительского процесса, например через диспетчер задач
 Почему тогда родительский процесс просто не завершается? Зачем ему дожидаться завершения дочернего?


Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
с использованием _execvpe

_execvpe вызывает тот же CreateProcess, а потом exit(0)...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
alexx83
Дата 21.12.2012, 08:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



Через CreateProcess вызываю так:
Код

memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));

CreateProcess(
    0    // exe name
    ,cmdbuf    // command line
    ,0            // process security attributes
    ,0            // primary thread security attributes
    ,FALSE        // handles are NOT inherited
    ,0            // creation flags
    ,0            // use parent's environment
    ,0            // use parent's current directory
    ,&si        // STARTUPINFO pointer
    ,&pi        // receives PROCESS_INFORMATION
)

WaitForSingleObject(pi.hProcess, INFINITE);
    
GetExitCodeProcess(pi.hProcess, &exitCode)
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );


PM MAIL   Вверх
alexx83
Дата 21.12.2012, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



Можете показать реализацию _execvpe?
PM MAIL   Вверх
feodorv
Дата 21.12.2012, 19:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(alexx83 @  21.12.2012,  09:02 Найти цитируемый пост)
Через CreateProcess вызываю так:

Вроде, всё на месте))) Поясните тогда, пожалуйста:
Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
При несанкционированном завершении родительского процесса, например через диспетчер задач, дочерний процесс остается висеть в памяти. 

Дочерний процесс в конце концов не завершается самостоятельно, или же просто Вам хочется, чтобы он умирал синхронно со смертью родительского?


Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
Необходимо в идеальном случае замещать родительский процесс дочерним с сохранением взаимодействия с консолью в дочернем процессе.

Почему тогда
Цитата(alexx83 @  21.12.2012,  09:02 Найти цитируемый пост)
WaitForSingleObject(pi.hProcess, INFINITE);

Почему не завершать родительский процесс сразу (ну, или после WaitForInputIdle)? Дочерний процесс теряет способность взаимодействия с консолью?


Цитата(alexx83 @  21.12.2012,  12:25 Найти цитируемый пост)
Можете показать реализацию _execvpe? 

Могу, но кода много и он относится к MSVS C++ 6.0.

Добавлено через 1 минуту и 35 секунд
Файл Execvpe.c
Код

/***
*execvpe.c - execute a file with given environ; search along PATH
*
*       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       defines _execvpe() - execute a file with given environ
*
*******************************************************************************/

#include <cruntime.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <mbstring.h>
#include <tchar.h>
#include <dbgint.h>

#define SLASHCHAR _T('\\')
#define XSLASHCHAR _T('/')

#define SLASH _T("\\")
#define DELIMITER _T(";")

#ifdef _MBCS
/* note, the macro below assumes p is to pointer to a single-byte character
 * or the 1st byte of a double-byte character, in a string.
 */
#define ISPSLASH(p)     ( ((p) == _mbschr((p), SLASHCHAR)) || ((p) == \
_mbschr((p), XSLASHCHAR)) )
#else  /* _MBCS */
#define ISSLASH(c)      ( ((c) == SLASHCHAR) || ((c) == XSLASHCHAR) )
#endif  /* _MBCS */


/***
*int _execvpe(filename, argvector, envvector) - execute a file
*
*Purpose:
*       Executes a file with given arguments and environment.
*       try to execute the file. start with the name itself (directory '.'),
*       and if that doesn't work start prepending pathnames from the
*       environment until one works or we run out. if the file is a pathname,
*       don't go to the environment to get alternate paths. If a needed text
*       file is busy, wait a little while and try again before despairing
*       completely
*
*Entry:
*       _TSCHAR *filename        - file to execute
*       _TSCHAR **argvector - vector of arguments
*       _TSCHAR **envvector - vector of environment variables
*
*Exit:
*       destroys the calling process (hopefully)
*       if fails, returns -1
*
*Exceptions:
*
*******************************************************************************/

int __cdecl _texecvpe (
        REG3 const _TSCHAR *filename,
        const _TSCHAR * const *argvector,
        const _TSCHAR * const *envptr
        )
{
        REG1 _TSCHAR *env;
        _TSCHAR *bbuf = NULL;
        REG2 _TSCHAR *buf;
        _TSCHAR *pfin;

        _ASSERTE(filename != NULL);
        _ASSERTE(*filename != _T('\0'));
        _ASSERTE(argvector != NULL);
        _ASSERTE(*argvector != NULL);
        _ASSERTE(**argvector != _T('\0'));

        _texecve(filename,argvector,envptr);

        if ( (errno != ENOENT)
        || (_tcschr(filename, SLASHCHAR) != NULL)
        || (_tcschr(filename, XSLASHCHAR) != NULL)
        || *filename && *(filename+1) == _T(':')
        || !(env=_tgetenv(_T("PATH"))) )
                goto reterror;

        /* allocate a buffer to hold alternate pathnames for the executable
         */
        if ( (buf = bbuf = _malloc_crt(_MAX_PATH * sizeof(_TSCHAR))) == NULL )
            goto reterror;

        do {
                /* copy a component into bbuf[], taking care not to overflow it
                 */
                /* UNDONE: make sure ';' isn't 2nd byte of DBCS char */
                while ( (*env) && (*env != _T(';')) && (buf < bbuf+(_MAX_PATH-2)*sizeof(_TSCHAR)) )
                        *buf++ = *env++;

                *buf = _T('\0');
                pfin = --buf;
                buf = bbuf;

#ifdef _MBCS
                if (*pfin == SLASHCHAR) {
                        if (pfin != _mbsrchr(buf,SLASHCHAR))
                                /* *pfin is the second byte of a double-byte
                                 * character
                                 */
                                strcat( buf, SLASH );
                }
                else if (*pfin != XSLASHCHAR)
                        strcat(buf, SLASH);
#else  /* _MBCS */
                if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR)
                        _tcscat(buf, SLASH);
#endif  /* _MBCS */

                /* check that the final path will be of legal size. if so,
                 * build it. otherwise, return to the caller (return value
                 * and errno rename set from initial call to _execve()).
                 */
                if ( (_tcslen(buf) + _tcslen(filename)) < _MAX_PATH )
                        _tcscat(buf, filename);
                else
                        break;

                _texecve(buf, argvector, envptr);

                if ( (errno != ENOENT)
#ifdef _MBCS
                && (!ISPSLASH(buf) || !ISPSLASH(buf+1)) )
#else  /* _MBCS */
                && (!ISSLASH(*buf) || !ISSLASH(*(buf+1))) )
#endif  /* _MBCS */
                        break;
        } while ( *env && env++ );

reterror:
        if (bbuf != NULL)
                _free_crt(bbuf);

        return(-1);
}


Добавлено через 2 минуты и 29 секунд
Файл Execve.c
Код

/***
*execve.c - execute a file with a given environment
*
*       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       defines _execve() - execute a file
*
*******************************************************************************/

#define EXECVE

#include "spawnve.c"


Добавлено через 3 минуты и 43 секунды
Файл Spawnve.c
Код

/***
*spawnve.c - Low level routine eventually called by all _spawnXX routines
*       also contains all code for _execve, called by _execXX routines
*
*       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*       This is the low level routine which is eventually invoked by all the
*       _spawnXX routines.
*
*       This is also the low-level routine which is eventually invoked by
*       all of the _execXX routines.
*
*******************************************************************************/

#include <cruntime.h>
#include <io.h>
#include <process.h>
#include <errno.h>
#include <msdos.h>
#include <string.h>
#include <stdlib.h>
#include <internal.h>
#include <mbstring.h>
#include <tchar.h>
#include <dbgint.h>

#define SLASHCHAR   _T('\\')
#define XSLASHCHAR  _T('/')

#ifndef EXECVE
#ifdef WPRFLAG
static int __cdecl wcomexecmd(int mode, const wchar_t * name,
        const wchar_t * const * argv, const wchar_t * const * envp);
#else  /* WPRFLAG */
static int __cdecl comexecmd(int mode, const char * name,
        const char * const * argv, const char * const * envp);
#endif  /* WPRFLAG */
#else  /* EXECVE */
#ifdef WPRFLAG
static int __cdecl wcomexecmd(const wchar_t * name,
        const wchar_t * const * argv, const wchar_t * const * envp);
#else  /* WPRFLAG */
static int __cdecl comexecmd(const char * name,
        const char * const * argv, const char * const * envp);
#endif  /* WPRFLAG */
#endif  /* EXECVE */

/***
*static int comexecmd(mode, name, argv, envp) - do the exec
*       or spawn after name fixup
*
*Purpose:
*       Spawns a child process with given parameters and environment.  Either
*       overlays current process or loads in free memory while parent process
*       waits.  If the named file is a .cmd file, modifies the calling sequence
*       and prepends the /c and filename arguments into the command string
*
*       Exec doesn't take a mode; instead, the parent process goes away as
*       the child process is brought in.
*
*Entry:
*       int mode - mode to spawn (WAIT, NOWAIT, or OVERLAY)
*                   only WAIT and OVERLAY currently supported
*
*           ****  mode is only used in the spawnve() version  ****
*
*       _TSCHAR *name - pathname of file to spawn.  Includes the extension
*       _TSCHAR **argv - vector of parameter strings
*       _TSCHAR **envp - vector of environment variables
*
*Exit:
*       returns exit code of child process
*       if fails, returns -1
*
*Exceptions:
*       Returns a value of (-1) to indicate an error in exec'ing the child
*       process.  errno may be set to:
*
*       E2BIG   = failed in argument/environment processing (_cenvarg)
*                 argument list or environment too big;
*       EACCESS = locking or sharing violation on file;
*       EMFILE  = too many files open;
*       ENOENT  = failed to find program name - no such file or directory;
*       ENOEXEC = failed in exec - bad executable format;
*       ENOMEM  = failed in memory allocation (during malloc, or in
*                 setting up memory for executing child process).
*
*******************************************************************************/

#ifdef WPRFLAG
static int __cdecl wcomexecmd (
#else  /* WPRFLAG */
static int __cdecl comexecmd (
#endif  /* WPRFLAG */

#ifndef EXECVE
        REG3 int mode,
#endif  /* EXECVE */

        REG2 const _TSCHAR *name,
        const _TSCHAR * const *argv,
        const _TSCHAR * const *envp
        )
{
        _TSCHAR *argblk;
        _TSCHAR *envblk;
        REG4 int rc;

#ifdef WPRFLAG
        if (_wcenvarg(argv, envp, &argblk, &envblk, name) == -1)
#else  /* WPRFLAG */
        if (_cenvarg(argv, envp, &argblk, &envblk, name) == -1)
#endif  /* WPRFLAG */
                return -1;

#ifndef EXECVE
#ifdef WPRFLAG
        rc = _wdospawn(mode, name, argblk, envblk);
#else  /* WPRFLAG */
        rc = _dospawn(mode, name, argblk, envblk);
#endif  /* WPRFLAG */
#else  /* EXECVE */
#ifdef WPRFLAG
        rc = _wdospawn(_P_OVERLAY, name, argblk, envblk);
#else  /* WPRFLAG */
        rc = _dospawn(_P_OVERLAY, name, argblk, envblk);
#endif  /* WPRFLAG */
#endif  /* EXECVE */
        /* free memory */

        _free_crt(argblk);
        _free_crt(envblk);

        return rc;
}

/***
*int _spawnve(mode, name, argv, envp) - low level _spawnXX library function
*int _execve(name, argv, envp) - low level _execXX library function
*
*Purpose:
*       spawns or execs a child process; takes a single pointer to an argument
*       list as well as a pointer to the environment; unlike _spawnvpe,
*       _spawnve does not search the PATH= list in processing the name
*       parameter; mode specifies the parent's execution mode.
*
*Entry:
*       int mode    - parent process's execution mode:
*                     must be one of _P_OVERLAY, _P_WAIT, _P_NOWAIT;
*                     not used for _execve
*       _TSCHAR *name  - path name of program to spawn;
*       _TSCHAR **argv - pointer to array of pointers to child's arguments;
*       _TSCHAR **envp - pointer to array of pointers to child's environment
*                     settings.
*
*Exit:
*       Returns : (int) a status value whose meaning is as follows:
*               0        = normal termination of child process;
*               positive = exit code of child upon error termination
*                          (abort or exit(nonzero));
*               -1       = child process was not spawned;
*                          errno indicates what kind of error:
*                          (E2BIG, EINVAL, ENOENT, ENOEXEC, ENOMEM).
*
*Exceptions:
*       Returns a value of (-1) to indicate an error in spawning the child
*       process.  errno may be set to:
*
*       E2BIG   = failed in argument/environment processing (_cenvarg) -
*                 argument list or environment too big;
*       EINVAL  = invalid mode argument;
*       ENOENT  = failed to find program name - no such file or directory;
*       ENOEXEC = failed in spawn - bad executable format;
*       ENOMEM  = failed in memory allocation (during malloc, or in
*                 setting up memory for spawning child process).
*
*******************************************************************************/

/* Extension array - ordered in search order from right to left.

   ext_strings  = array of extensions
*/

static _TSCHAR *ext_strings[] = { _T(".cmd"), _T(".bat"), _T(".exe"), _T(".com") };
enum {CMD, BAT, EXE, COM, EXTFIRST=CMD, EXTLAST=COM};

int __cdecl

#ifndef EXECVE

_tspawnve (
        REG3 int mode,

#else  /* EXECVE */

_texecve (

#endif  /* EXECVE */

        const _TSCHAR *name,
        const _TSCHAR * const *argv,
        const _TSCHAR * const *envp
        )
{
        _TSCHAR *ext;   /* where the extension goes if we have to add one */
        REG1 _TSCHAR *p;
        _TSCHAR *q;
        REG2 _TSCHAR *pathname = (_TSCHAR *)name;
        REG4 int rc;
        REG5 int i;

        p = _tcsrchr(pathname, SLASHCHAR);
        q = _tcsrchr(pathname, XSLASHCHAR);

        /* ensure that pathname is an absolute or relative pathname. also,
         * position p to point at the filename portion of pathname (i.e., just
         * after the last occurence of a colon, slash or backslash character */

        if (!q) {
                if (!p)
                        if (!(p = _tcschr(pathname, _T(':')))) {

                                /* pathname is a filename only, force it to be
                                 * a relative pathname. note that an extra byte
                                 * is malloc-ed just in case pathname is NULL,
                                 * to keep the heap from being trashed by
                                 * strcpy */
                                if (!(pathname = _malloc_crt((_tcslen(pathname) + 3) * sizeof(_TSCHAR))))
                                        return(-1);

                                _tcscpy(pathname, _T(".\\"));
                                _tcscat(pathname, name);

                                /* set p to point to the start of the filename
                                 * (i.e., past the ".\\" prefix) */
                                p = pathname + 2;
                        }
                        /* else pathname has drive specifier prefix and p is
                         * is pointing to the ':' */
        }
        else if (!p || q > p)   /* p == NULL or q > p */
                p = q;


        rc = -1;        /* init to error value */

        if (ext = _tcsrchr(p, _T('.')))  {

                /* extension given; only do filename */

                if (_taccess(pathname, 0) != -1) {

#ifndef EXECVE

#ifdef WPRFLAG
                        rc = wcomexecmd(mode, pathname, argv, envp);
#else  /* WPRFLAG */
                        rc = comexecmd(mode, pathname, argv, envp);
#endif  /* WPRFLAG */

#else  /* EXECVE */

#ifdef WPRFLAG
                        rc = wcomexecmd(pathname, argv, envp);
#else  /* WPRFLAG */
                        rc = comexecmd(pathname, argv, envp);
#endif  /* WPRFLAG */

#endif  /* EXECVE */
                }

        }
        else    {

                /* no extension; try .cmd/.bat, then .com and .exe */

                if (!(p = _malloc_crt((_tcslen(pathname) + 5) * sizeof(_TSCHAR))))
                        return(-1);

                _tcscpy(p, pathname);
                ext = p + _tcslen(pathname);

                for (i = EXTLAST; i >= EXTFIRST; --i) {
                        _tcscpy(ext, ext_strings[i]);

                        if (_taccess(p, 0) != -1) {

#ifndef EXECVE
#ifdef WPRFLAG
                                rc = wcomexecmd(mode, p, argv, envp);
#else  /* WPRFLAG */
                                rc = comexecmd(mode, p, argv, envp);
#endif  /* WPRFLAG */
#else  /* EXECVE */
#ifdef WPRFLAG
                                rc = wcomexecmd(p, argv, envp);
#else  /* WPRFLAG */
                                rc = comexecmd(p, argv, envp);
#endif  /* WPRFLAG */
#endif  /* EXECVE */
                                break;
                        }
                }
                _free_crt(p);
        }

        if (pathname != name)
                _free_crt(pathname);

        return rc;
}


Добавлено через 6 минут и 17 секунд
Остальное через 15 минут)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
alexx83
Дата 21.12.2012, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



На работе вроде отправлял сообщение сюда что реализацию _execvpe нашел которую вы выложили. Все равно спасибо! Не нашел только реализацию функции comexecmd() - msdn ничего не нашел и в студии тоже не нашел. 

Цитата

Дочерний процесс в конце концов не завершается самостоятельно, или же просто Вам хочется, чтобы он умирал синхронно со смертью родительского?

Да нужно чтобы процессы умирали синхронно.

Цитата

Почему не завершать родительский процесс сразу (ну, или после WaitForInputIdle)? Дочерний процесс теряет способность взаимодействия с консолью?

А можно по подробнее? После CreateProcess просто делать exit?
PM MAIL   Вверх
feodorv
Дата 21.12.2012, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Файл Dospawn.c
Код

/***
*dospawn.c - spawn a child process
*
*       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       defines _dospawn - spawn a child process
*
*******************************************************************************/

#include <cruntime.h>
#include <oscalls.h>
#include <internal.h>
#include <msdos.h>
#include <process.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <tchar.h>
#include <dbgint.h>

#ifndef WPRFLAG
int _p_overlay = 2;
#endif  /* WPRFLAG */

/***
*int _dospawn(mode, name, cmdblk, envblk) - spawn a child process
*
*Purpose:
*       Spawns a child process
*
*Entry:
*       int mode     - _P_WAIT, _P_NOWAIT, _P_NOWAITO, _P_OVERLAY, or _P_DETACH
*       _TSCHAR *name   - name of program to execute
*       _TSCHAR *cmdblk - parameter block
*       _TSCHAR *envblk - environment block
*
*Exit:
*       _P_OVERLAY: -1 = error, otherwise doesn't return
*       _P_WAIT:    termination code << 8 + result code
*       _P_DETACH: -1 = error, 0 = success
*       others:    PID of process
*
*Exceptions:
*
*******************************************************************************/

#ifdef WPRFLAG
int __cdecl _wdospawn (
#else  /* WPRFLAG */
int __cdecl _dospawn (
#endif  /* WPRFLAG */
        int mode,
        const _TSCHAR *name,
        _TSCHAR *cmdblk,
        _TSCHAR *envblk
        )
{
        char syncexec, asyncresult, background;
        LPTSTR CommandLine;
        STARTUPINFO StartupInfo;
        PROCESS_INFORMATION ProcessInformation;
        BOOL CreateProcessStatus;
        ULONG dosretval;                /* OS return value */
        DWORD retval;
        DWORD fdwCreate = 0;            /* flags for CreateProcess */
        int i;
        ioinfo *pio;
        char *posfile;
        UNALIGNED long *posfhnd;
        int nh;                         /* number of file handles to be
                                           passed to the child */

        /* translate input mode value to individual flags */
        syncexec = asyncresult = background = 0;
        switch (mode) {
        case _P_WAIT:    syncexec=1;    break;  /* synchronous execution */
        case 2: /* _P_OVERLAY */
        case _P_NOWAITO: break;                 /* asynchronous execution */
        case _P_NOWAIT:  asyncresult=1; break;  /* asynch + remember result */
        case _P_DETACH:  background=1;  break;  /* detached in null scrn grp */
        default:
            /* invalid mode */
            errno = EINVAL;
            _doserrno = 0;              /* not a Dos error */
            return -1;
        }

        /*
         * Loop over null separate arguments, and replace null separators
         * with spaces to turn it back into a single null terminated
         * command line.
         */
        CommandLine = cmdblk;
        while (*cmdblk) {
            while (*cmdblk) {
                cmdblk++;
            }

            /*
             * If not last argument, turn null separator into a space.
             */
            if (cmdblk[1] != _T('\0')) {
                *cmdblk++ = _T(' ');
            }
        }

        memset(&StartupInfo,0,sizeof(StartupInfo));
        StartupInfo.cb = sizeof(StartupInfo);

        for ( nh = _nhandle ;
              nh && !_osfile(nh - 1) ;
              nh-- ) ;

        StartupInfo.cbReserved2 = (WORD)(sizeof( int ) + (nh *
                                  (sizeof( char ) + sizeof( long ))));

        StartupInfo.lpReserved2 = _calloc_crt( StartupInfo.cbReserved2, 1 );

        *((UNALIGNED int *)(StartupInfo.lpReserved2)) = nh;

        posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int ));

        posfhnd = (UNALIGNED long *)(StartupInfo.lpReserved2 + sizeof( int ) +
                  (nh * sizeof( char )));

        for ( i = 0,
              posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int )),
              posfhnd = (UNALIGNED long *)(StartupInfo.lpReserved2 +
                        sizeof( int ) + (nh * sizeof( char ))) ;
              i < nh ;
              i++, posfile++, posfhnd++ )
        {
            pio = _pioinfo(i);
            if ( (pio->osfile & FNOINHERIT) == 0 ) {
                *posfile = pio->osfile;
                *posfhnd = pio->osfhnd;
            }
            else {
                *posfile = 0;
                *posfhnd = (long)INVALID_HANDLE_VALUE;
            }
        }

        /*
         * if the child process is detached, it cannot access the console, so
         * we must nuke the information passed for the first three handles.
         */
        if ( background ) {

            for ( i = 0,
                  posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int )),
                  posfhnd = (UNALIGNED long *)(StartupInfo.lpReserved2 + sizeof( int )
                            + (nh * sizeof( char ))) ;
                  i < __min( nh, 3 ) ;
                  i++, posfile++, posfhnd++ )
            {
                *posfile = 0;
                *posfhnd = (long)INVALID_HANDLE_VALUE;
            }

            fdwCreate |= DETACHED_PROCESS;
        }

        /**
         * Set errno to 0 to distinguish a child process
         * which returns -1L from an error in the spawning
         * (which will set errno to something non-zero
        **/

        _doserrno = errno = 0 ;

#ifdef WPRFLAG
        /* indicate to CreateProcess that environment block is wide */
        fdwCreate |= CREATE_UNICODE_ENVIRONMENT;
#endif  /* WPRFLAG */

        CreateProcessStatus = CreateProcess( (LPTSTR)name,
                                             CommandLine,
                                             NULL,
                                             NULL,
                                             TRUE,
                                             fdwCreate,
                                             envblk,
                                             NULL,
                                             &StartupInfo,
                                             &ProcessInformation
                                           );

        dosretval = GetLastError();
        _free_crt( StartupInfo.lpReserved2 );

        if (!CreateProcessStatus) {
            _dosmaperr(dosretval);
            return -1;
        }

        if (mode == 2 /* _P_OVERLAY */) {
            /* destroy ourselves */
            _exit(0);
        }
        else if (mode == _P_WAIT) {
            WaitForSingleObject(ProcessInformation.hProcess, (DWORD)(-1L));

            /* return termination code and exit code -- note we return
               the full exit code */
            GetExitCodeProcess(ProcessInformation.hProcess, &retval);

            CloseHandle(ProcessInformation.hProcess);
        }
        else if (mode == _P_DETACH) {
            /* like totally detached asynchronous spawn, dude,
               close process handle, return 0 for success */
            CloseHandle(ProcessInformation.hProcess);
            retval = (DWORD)0;
        }
        else {
            /* asynchronous spawn -- return PID */
            retval = (DWORD)ProcessInformation.hProcess;
        }

        CloseHandle(ProcessInformation.hThread);
        return retval;
}


Добавлено через 8 минут и 13 секунд
Цитата(alexx83 @  21.12.2012,  20:45 Найти цитируемый пост)
Да нужно чтобы процессы умирали синхронно.

Это делается через job'ы.


Цитата(alexx83 @  21.12.2012,  20:45 Найти цитируемый пост)
А можно по подробнее? После CreateProcess просто делать exit? 

Из main (etc) можно просто return))) Или ExitProcess. exit - это как-то для stdlib.
Но я бы предварительно сделал WaitForInputIdle на всякий случай...


Цитата(alexx83 @  21.12.2012,  20:45 Найти цитируемый пост)
Не нашел только реализацию функции comexecmd()

См. вышеприведённый файл Spawnve.c smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
alexx83
Дата 21.12.2012, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



Если делаю так:
Код

CreateProcess(
    0    // exe name
    ,cmdbuf    // command line
    ,0            // process security attributes
    ,0            // primary thread security attributes
    ,FALSE        // handles are NOT inherited
    ,0            // creation flags
    ,0            // use parent's environment
    ,0            // use parent's current directory
    ,&si        // STARTUPINFO pointer
    ,&pi        // receives PROCESS_INFORMATION
);
    
WaitForInputIdle(pi.hProcess, INFINITE);
    
free(envbuf);
free(resbuf);
free(cmdbuf);
    
ExitProcess(0);

То получаю такой же результат как при использовании _execvpe, т.е. могу ввести только одну команду в консоли дочернему процессу и он отрубается от консоли
PM MAIL   Вверх
alexx83
Дата 21.12.2012, 21:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



Сделал через jobs:
Код

HANDLE ghJob = CreateJobObject( NULL, "Gdb-Wrapper\0"/*NULL*/);
if( ghJob == NULL)
{
    printf("Could not create job object\n");
}
else
{
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
    // Configure all child processes associated with the job to terminate when the
    jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    if( 0 == SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
    {
        printf("Could not SetInformationJobObject\n");
    }
}

memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
    
memset(&pi, 0, sizeof(pi));

CreateProcess(
    0    // exe name
    ,cmdbuf    // command line
    ,0            // process security attributes
    ,0            // primary thread security attributes
    ,FALSE        // handles are NOT inherited
    ,0            // creation flags
    ,0            // use parent's environment
    ,0            // use parent's current directory
    ,&si        // STARTUPINFO pointer
    ,&pi        // receives PROCESS_INFORMATION
);
    
if( 0 == AssignProcessToJobObject( ghJob, pi.hProcess))
{
    printf("Could not AssignProcessToObject\n");
}
WaitForSingleObject(pi.hProcess, INFINITE);

GetExitCodeProcess(pi.hProcess, &exitCode);
    
//CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
    
free(envbuf);
free(resbuf);
free(cmdbuf);
    
return exitCode;

Единственное если снимаю родительский процесс через менеджер процессов, то опять получаю:
Код

$ Exception condition detected on fd 0
error detected on stdin

Можно от этого избавиться?
PM MAIL   Вверх
feodorv
Дата 21.12.2012, 23:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(alexx83 @  21.12.2012,  21:27 Найти цитируемый пост)
То получаю такой же результат как при использовании _execvpe, т.е. могу ввести только одну команду в консоли дочернему процессу и он отрубается от консоли 

Даже не знаю, что сказать. Я бы ещё поэкспериментировал с флагом наследования, с GetConsoleProcessList() и т.д., но на всё это нужно время...

 
Цитата(alexx83 @  21.12.2012,  22:21 Найти цитируемый пост)
Единственное если снимаю родительский процесс через менеджер процессов, то опять получаю:

Опять-таки, не знаю, чем помочь...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
boostcoder
Дата 22.12.2012, 00:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: нет
Всего: 110



feodorv, здравствуй.
уже и мне сабж любопытен.

давай начнем сначала, а то я запутался...
скажи, каким образом я могу запустить дочерний процесс так, чтоб он унаследовал дескрипторы стандартного ввода/вывода, и чтоб по завершению родительского процесса завершался дочерний?
в линукс это решается банальным использованием fork() в родительском, и exec*() в дочернем.

спасибо.

PM WWW   Вверх
boostcoder
Дата 22.12.2012, 00:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: нет
Всего: 110



но в данном случае fork() лишний, да.

PM WWW   Вверх
feodorv
Дата 22.12.2012, 04:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



boostcoder, здравствуй  smile 

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


Цитата(boostcoder @  22.12.2012,  01:04 Найти цитируемый пост)
скажи, каким образом я могу запустить дочерний процесс так, чтоб он унаследовал дескрипторы стандартного ввода/вывода

Это первая часть вопроса, не менее важная, чем вторая. Вот здесь сказано, что если при вызове CreateProcess (для консольного экзешника) не пользоваться флагами  CREATE_NEW_CONSOLE и DETACHED_PROCESS, то дочерний процесс остаётся прикреплённым к консоли родительского процесса. Правда, я лично обычно всё же выставлял bInheritHandles в TRUE, а в STARTUPINFO устанавливал стандартные хендлеры не смотря на то, что это, вроде, и не требуется:
Цитата
the parent's standard handles are inherited by any child process
 (заимствовано отсюда), но никогда не прибивал родительский процесс раньше времени, чтобы посмотреть, что там случилось с дочерним. Там же нашёл интересную фразу:
Цитата
If this flag is not specified when a console process is created, both processes are attached to the same console, and there is no guarantee that the correct process will receive the input intended for it. Applications can prevent confusion by creating child processes that do not inherit handles of the input buffer, or by enabling only one child process at a time to inherit an input buffer handle while preventing the parent process from reading console input until the child has finished.
 Возможно, в ней кроется разрешение проблемы alexx83, возможно, нет.

Почему всё-таки прописываю стандартные хендлеры в STARTUPINFO, хотя эта структура должна бы иметь смысл только при создании новой консоли. 
Цитата
Important  The caller is responsible for ensuring that the standard handle fields in STARTUPINFO contain valid handle values. These fields are copied unchanged to the child process without validation, even when the dwFlags member specifies STARTF_USESTDHANDLES. Incorrect values can cause the child process to misbehave or crash.
 (взято отсюда). Возможно, в этом кроется разрешение проблемы alexx83, возможно, нет.


Цитата(boostcoder @  22.12.2012,  01:04 Найти цитируемый пост)
и чтоб по завершению родительского процесса завершался дочерний?

Никак. Дочерний процесс в огромной степени независим от родительского, если не объединять их в "задания". alexx83 очень хорошо реализовал эту схему, да, с неприятным сайд эффектом... Вполне возможно, что смерть родительского процесса каким-то образом сказывается на консоли (т.е. отсоединяет от неё дочерний процесс), к сожалению, опыта работы с такими ситуациями нет.


Цитата(alexx83 @  20.12.2012,  22:45 Найти цитируемый пост)
одно и которых при запуске меняет часть переменных среды

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


А может, дело в самом экзешнике дочернего процесса, как я понял, это gdb. Возможно, это он хитро реагирует на смерть родительского процесса.

Добавлено через 4 минуты и 6 секунд
Цитата(feodorv @  22.12.2012,  05:54 Найти цитируемый пост)
If this flag is not specified

Имеется в виду CREATE_NEW_CONSOLE.

Добавлено через 10 минут и 39 секунд
Цитата(feodorv @  22.12.2012,  05:54 Найти цитируемый пост)
Никак.

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


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
alexx83
Дата 22.12.2012, 08:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 17
Регистрация: 29.3.2010

Репутация: нет
Всего: 1



Сделал с заполнением хэндлов
Код

        memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    
    memset(&pi, 0, sizeof(pi));

    CreateProcess(
         0    // exe name
        ,cmdbuf    // command line
        ,0            // process security attributes
        ,0            // primary thread security attributes
        ,TRUE        // handles are NOT inherited
        ,0            // creation flags
        ,0            // use parent's environment
        ,0            // use parent's current directory
        ,&si        // STARTUPINFO pointer
        ,&pi        // receives PROCESS_INFORMATION
    );

Результат такой же как и без заполнения smile
PM MAIL   Вверх
boostcoder
Дата 22.12.2012, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: нет
Всего: 110



как я понял, семейство функций exec*() работает не так как в POSIX, хотя именно для этого эти функции и предоставляются msvcrt.dll.

PM WWW   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.1168 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.