Параметры lpApplicationName и lpCommandLine



Эти параметры определяют имя исполняемого файла нового процесса и командную строку, передаваемую этому процессу.

Чаще всего указывают lp ApplicationName == NULL, поскольку имя запускаемого файла все равно должно быть указано в параметре lpCommandLine, которыйдолжен содержатьполную командную строку создания нового процесса. Разбирая эту строку, функция полагает, что первый компонент в ней представляет собой имя исполняемого файла, который Вы хотите запустить. Если в имени этого файла не указано расширение, она считает его EXE. Далее функция приступает к поиску заданного файла и делает это в следующем порядке:

 

  1. Каталог, содержащий ЕХЕ-файл вызывающего процесса.
  2. Текущий каталог вызывающего процесса.
  3. Системный каталог Windows.
  4. Основной каталог Windows.
  5. Каталоги, перечисленные в переменной окружения PATH.

 

Конечно, если в имени файла указан полный путь доступа, система сразу обращается туда и не просматривает эти каталоги. Найдя нужный исполняемый файл, она создает новый процесс, проецирует код и данные исполняемого файла на адресное пространство этого процесса и обращается к процедурам стартового кода библиотеки С/С++. Тот в свою очередь анализирует командную строку процесса и передает WinMain адрес первого (за именем исполняемого файла) аргумента как lp C ommand Line.

Параметры   lpProcessAttributes, lpThreadAttributes

Чтобы создать новый процесс, система должна сначала создать объекты ядра "процесс" и "поток" (для первичного потока процесса). Поскольку это объекты ядра, родительский процесс получает возможность связать с ними атрибуты защиты. Эти параметры позволяют определить нужные атрибуты защиты для объектов "процесс" и "поток" соответственно. В эти параметры можно занести NULL, и система закрепит за данными объектами дескрипторы защиты по умолчанию. В качестве альтернативы можно объявить и инициализировать две структуры SECURITY_ATTRIBUTES, чтобы присвоить объектам "процесс" и "поток" свои атрибуты защиты.

Параметр   blnheritHandles

 

Обычно устанавливается в false. При true новый процесс наследует каждый наследуемый дескриптор, открытый в вызывающем процессе.

Параметр dwCreationFlags

Является комбинацией битовых флагов. Одна группа битовых флагов устанавливает способ создания процесса, другая – флаги приоритета процесса. Флаги комбинируются булевым оператором OR.

 

 

Флаги, влияющие на то, как именно создается новый процесс. 

 

  • Флаг DEBUG_PROCESS даст возможность родительскому процессу проводить отладку дочернего, а также всех процессов, которые последним могут быть порождены Если этот флаг установлен, система уведомляет родительский процесс (он теперь получает статус отладчика) о возникновении определенных событий в любом из дочерних процессов (а они получают статус отлаживаемых).
  • Флаг DEBUG_ONLY_THIS_PROCESS аналогичен флагу DEBUG_PROCESS с тем исключением, что заставляет систему уведомлять родительский процесс о возникновении специфических событий только в одном дочернем процессе — его прямом потомке. Тогда, если дочерний процесс создаст ряд дополнительных, отладчик уже не уведомляется о событиях, "происходящих" в них.
  • Флаг CREATE_SUSPENDED позволяет создать процесс и в то же время приостановить его первичный поток. Это позволяет родительскому процессу изменить приоритет дочернего процесса до того, как он получит шанс на выполнение. Внеся нужные изменения, родительский процесс разрешает выполнение дочернего вызовом функции ResumeThread (дескриптор).
  • Флаг DETACHED_PROCESS блокирует доступ процессу, инициированному консольной программой, к созданному родительским процессом консольному окну и сообщает системе, что вывод следует перенаправить в новое окно.
  • Флаг CREATE_NEW_CONSOLE приводит к созданию нового консольного окна для нового процесса. Имейте в виду, что одновременная установка флагов CREATE_NEW_CONSOLE и DETACHED_PROCESS недопустима.
  • Флаг CREATE_NO_WINDOW запрещает создание консольных окон для данного приложения и тем самым позволяет исполнять его без пользовательского интерфейса.
  • Флаг CREATE_NEW_PROCESS_GROUP служит для модификации списка процессов, уведомляемых о нажатии клавиш Ctrl+C и Ctrl+Break. Если в системе одновременно исполняется несколько CUI-процессов, то при нажатии одной из упомянутых комбинаций клавиш система уведомляет об этом только процессы, включенные в группу. Указав этот флаг при создании нового СUI-процесca, Вы создаете и новую группу
  • Флаг CREATE_DEFAULT_ERROR_MODE сообщает системе, чтo новый процесс не должен наследовать режимы обработки ошибок, установленные в родительском
  • Флаг CREATE_SEPARATE_WOW VDM полезен только при запуске 16-разрядного Windows-приложения. Если он установлен, система создает отдельную виртуальную DOS-машину (Virtual DOS-machine, VDM) и запускает 16-разрядное Windows-приложение именно в ней (По умолчанию все 16 разрядные Windows-приложения выполняются в одной, общей VDM). Выполнение приложения в отдельной VDM дает большое преимущество - "рухнув", приложение уничтожит лишь эту VDM, а программы, выполняемые в других VDM, продолжат нормальную работу. Кроме того, 16-разрядные Windows-приложения, выполняемые в раздельных VDM, имеют и раздельные очереди ввода. Эго значит, что, если одно приложение вдруг "зависнет", приложения в других VDM продолжат прием ввода. Единственный недостаток работы с несколькими VDM в том, что каждая из них требует значительных объемов физической памяти.
  • Флаг CREATE_SHARED_WOW_VDM полезен только при запуске 16-разрядного Windows-приложения . По умолчанию все 16-разрядные Windows-приложения выполняются в одной VDM, если только не указан флаг CREATE_SEPARATEWOW_VDM. Однако стандартное пoвeдeниeWindows 2000 можно изменить, присвоив значение "yes" параметру DefaultSeparateVDM в paздeлe HKEY_LOCAL_MACHINE\System\CurгentControlSet\Contгol\WOW. (Пocле модификации этого параметра систему надо перезагрузить.) Установив значение "yes", но указав флаг CREATE_SHARED_WOW_VDM, Вы вновь заставите выполнять все 16-разрядные Windows-приложения в одной VDM.
  • Флаг CREATE_UNICODE_ENVIRONMENT сообщает системе, что блок переменных окружения дочернего процесса должен содержать Unicode-символы. По умолчанию блок формируется на основе ANSI-символов.
  • Флаг CREATE_FORCEDOS заставляет систему выполнять программу MS-DOS, встроенную в 16-разрядное приложение OS/2.
  • Флаг CREATE_BREAKAWAY_FROM_JOB позволяет процессу, включенному в задание, создать новый процесс, отделенный от этого задания .

 

Параметр dwCreat ionFlags  разрешает задать и класс приоритета процесса. Однако это необязательно и даже, как правило, не рекомендуется - система присваивает новому процессу класс приоритета по умолчанию. Возможные классы приоритета перечислены в следующей таблице.

 

Класс приоритета     Флаговый идентификатор
Idle (простаивающий) IDLE_PRIORITY_CLASS
Below normal (ниже обычного) BELOW_NORMAL_PRIORITY_CLASS
Normal (обычный) NORMAL PRIORITY CLASS
Above normal (выше обычного) ABOVE_NORMAL_PRIORITY_CLASS
High (высокий) HIGH_PRIORITY_CLASS
Realtime (реального времени) REALTIME_PRIORITY_CLASS

 

Классы приоритета влияют на распределение процессорного времени между процессами и их потоками.

Параметр lpEnvironment

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

 

Параметр lpCurrentDirectory

Он позволяет родительскому процессу установить текущие диск и каталог для дочернего процесса. Если его значение — NULL, рабочий каталог нового процесса будет тем же, что и у приложения, его породившего. А если он отличен от NULL, то должен указывать на строку (с нулевым символом в конце), содержащую нужный диск и каталог. В путь надо включать и букву диска.

 

Параметр lpStartuplnfo

Этот параметр указывает на структуру STARTUPINFO:

 

typedef struct _STARTUPINFO {
                        DWORD cb;
                        PSTR lpReserved;
                        PSTR lpDesktop;
                        PSTR lpTitle;
                        DWORD dwX;
                        DWORD dwY;

                        DWORD dwXSize;
                        DWORD dwYSize;
                        DWORD dwXCountChars;
                        DWORD dwYCountChars;
                        DWORD dwFillAttribute;
                        DWORD dwFlags;
                        WORD wShowWindOw;
                        WORD cbReserved2;
                        PBYTE lpReserved2;
                        HANDLE hStdInput;
                        HANDLE hStdOutput;
                        HANDLE hStdError;
                     } STARTUPINFO, *LPSTARTUPINFO;

 

     Элементы структуры STARTUPINFO используются Windows-функциями

     при создании нового процесса.

 

Поясним один элемент -  dwFlags . Он содержит набор флагов, позволяющих управлять созданием дочернего процесса. Большая часть флагов просто сообщает функции CreateProcess , содержат ли прочие элементы структуры STARTUPINFO полезную информацию или некоторые из них можно игнорировать. Список допустимых флагов приведен в следующей таблице.

 

Флаг Описание
STARTF_USESIZE Заставляет использовать элементы divSize и dwYSize
STARTF_USESHOWWINDOW Заставляет использовать элемент wShowWindow
STARTF_USEPOSITION Заставляет использовать элементы dwX и dwY
STARTF_USECOTUNTCHARS Заставляет использовать элементы dwXCountChars и dwYCountCbars
STARTF_USEFILLATTRIBUTE Заставляет использовать элемент dwFillAttnbute
STARTF_USESTDHANDLES Заставляет использовать элементы hStdlnput , hStdOutput и bStdError

 

STARTF_RUN_FULLSCREEN Приводит к тому, что консольное приложение на компьютере с процессором типа х86 запускается в полноэкран ном режиме

 

Параметр ppiProclnfo

Параметр ppiProcInfo указывает на структуру PROCESS_INFORMATION, которую Вы должны предварительно создать; ее элементы инициализируются самой функцией CreateProcess. Структура представляет собой следующее:

 

 

typedef struct _PROCESS_INFORMATION {
                                  HANDLE hProcess;
                                  HANDLE hThread;
                                  DWORD dwProcessId;
                                  DWORD dwThreadId;


                               } PROCESS_INFORMATION;

 

Значения элементов структуры:

 

hProcess     - дескриптор созданного процесса

hThread      - дескриптор первичного потока созданного процесса

 dwProcessId   - глобальный идентификатор процесса

dwThreadId  - глобальный идентификатор потока.

 

       Дескриптор и идентификатор – это не одно и то же. Дескриптор используется для указания объекта во всех функциях, выполняющих операции над объектом. Он имеет смысл только в пределах данного процесса и его нельзя передавать из процесса в процесс.

Идентификатор процесса предназначен для идентификации процесса другими процессами. Его можно передавать из одного процесса в другой. Для управления процессом из другого процесса нужно обратиться к функции OpenProcess(), которой передается идентификатор управляемого процесса.

 

Примечания.

 

1. Если известен дескриптор процесса, то его можно завершить принудительно. Например, если основной процесс создал дочерний процесс, заполнив свою структуру PROCESS_INFORMATION pinfo, то он же может его завершить так:

TerminateProcess(pinfo.hProcess, 0);

 

2. Если порожденный процесс имеет только один поток с дескриптором окна hWnd, то его можно завершить, послав окну (не потоку!!) сообщение WM_CLOSE:

SendMessage(hWnd, WM_CLOSE,0,0);  

 

 

Разумеется, нужно знать дескриптор окна. Его можно получить, вызвав функцию:

            hWnd = FindWindow(<имя_класса_окна>,<текст_заголовка_окна>);

 

В Builder имя класса окна получается из имени формы с добавлением в начале символа T (например, TForm1). Если имя класса неизвестно, то для окон верхнего уровня вместо имени класса пишется NULL.

 

Еще одна возможность узнать имя класса - запустить программу WinSight32 (входит в поставку С++Builder и MSVC. После выполнения команды меню Spy-Find Window на экран выводится список всех зарегистрированных окон, класс окна в “{...}” и последним параметром - заголовок окна.

 

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

также обнулять структуру PROCESS_INFORMATION.

 

    Разработчики приложений часто забывают о необходимости

    инициализации этих структур.

 

Если Вы не обнулите их элементы, в них будет содержаться мусор, оставшийся в стеке вызывающего потока. Функция CreateProcess , получив такую структуру данных, либо создаст новый процесс, либо нет — все зависит от того, что именно окажется в этом мусоре.

 

Поэтому базовый вариант обращения к функции таков:

 

 STARTUPINFO          sinfo;

 PROCESS_INFORMATION pinfo;

 memset(&pinfo, 0, sizeof(pinfo));

 memset(&sinfo, 0, sizeof(sinfo));

 sinfo.cb = sizeof(sinfo);

 

 CreateProcess(NULL,”c:\\prg\\my.exe”, NULL, NULL, false, 0,

                             NULL, NULL, &sinfo, &pinfo};

 

 

Функция CreateProcess() возвращается без ожидания окончания инициализации порожденного процесса. Если нужно немедленно начать взаимодействие с порожденным процессом, то нужно дождаться окончания инициализации путем вызова функции:

 

    WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds).

 

где hProcess – дескриптор процесса (брать как элемент структуры PROCESS_INFORMATION), dwMilliseconds - время ожидания.

   

 

Эта функция возвращается, если порожденный процесс инициирован или истекло время ожидания:

 

Возвращаемое значение                  Пояснение
0 Порожденный процесс инициирован
WAIT_TIMEOUT Истек интервал ожидания
0xFFFFFFFF Ошибка (код ошибки по GetLastError())

 

 

Как уже говорилось, создание нового процесса влечет за собой создание объектов ядра "процесс" и "поток". В момент создания система присваивает счетчику каждого объекта начальное значение - единицу. Далее функция CreateProcess открывает объекты "процесс" и "поток" и заносит их описатели, специфичные для данного процесса, в элементы hProcess и hTbread структуры PROCESS_INFORMATION. Когда CreateProce ss открывает эти объекты, счетчики каждого из них увеличиваются до 2.

Это означает, что, перед тем как система сможет высвободить из памяти объект "процесс", процесс должен быть завершен (счетчик уменьшен до 1), а родительский процесс обязан вызвать функцию CloseHandle (и тем самым обнулить счетчик). То же самое относится и к объекту "поток" - поток должен быть завершен, а родительский процесс должен закрыть описатель объекта "поток".

 

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

 

 

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

 

 

Завершение процесса

Процесс можно завершить четырьмя способами:

 

  • входная функция первичного потока возвращает управление (рекомендуемый способ),
  • один из потоков процесса вызывает функцию ExitProcess (нежелательный способ);
  • поток другого процесса вызывает функцию TerminateProcess (тоже нежелательно);
  • Все потоки процесса умирают по своей воле (большая редкость),

 


Дата добавления: 2019-07-15; просмотров: 207; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!