Программирование для Windows NT© Александр Фролов, Григорий ФроловТом 26, часть 1, М.: Диалог-МИФИ, 1996, 272 стр. Рецензия PC WEEK Запуск процессаПользователь запускает процесс при помощи приложений Program Manager и File Manager. Он может также воспользоваться командной строкой в системном приглашении консоли Microsoft Windows NT. Что же касается приложения, то оно может выполнить эту задачу как при помощи уже известных вам из программирования для Microsoft Windows версии 3.1 функций WinExec XE "WinExec" и LoadModule XE "LoadModule" , так и при помощи функции CreateProcess XE "CreateProcess" , специально предназначенной для запуска процессов. Заметим, что с помощью этой функции в середе Microsoft Windows NT версии 3.51 для платформы Intel вы можете запустить как 32-разрядные, так и 16-разрядные приложения Windows, а также программы MS-DOS и 16-разрядные консольные приложения OS/2 (напомним, что первые версии операционной системы OS/2 разрабатывались совместно фирмами Microsoft и IBM). Параметры функции CreateProcessФункция CreateProcess имеет много параметров, однако ей не так сложно пользоваться, как это может показаться на первый взгляд: BOOL CreateProcess( LPCTSTR lpApplicationName, // указатель на имя исполняемого // модуля LPTSTR lpCommandLine, // указатель на командную строку LPSECURITY_ATTRIBUTES lpProcessAttributes, // указатель на // атрибуты защиты процесса LPSECURITY_ATTRIBUTES lpThreadAttributes, // указатель на // атрибуты защиты задачи BOOL bInheritHandles, // флаг наследования идентификатора DWORD dwCreationFlags,// флаги создания процесса LPVOID lpEnvironment, // указатель на блок среды выполнения LPCTSTR lpCurrentDirectory, // указатель на имя текущего // каталога LPSTARTUPINFO lpStartupInfo, // указатель на структуру // STARTUPINFO LPPROCESS_INFORMATION lpProcessInformation); // указатель на // структуру PROCESS_INFORMATION Если функция CreateProcess завершается успешно, она возвращает значение TRUE. В противном случае возвращается значение FALSE. Код ошибки вы можете получить, вызвав функцию GetLastError XE "GetLastError" . lpApplicationNamelpCommandLineПараметры lpApplicationName и lpCommandLine используются для указания имя программного файла и параметров запуска процесса. Вы можете использовать один или оба этих параметра. Через параметр lpApplicationName вы можете передать указатель на строку, закрытую двоичным нулем и содержащую полный либо частичный путь к программному файлу. При этом параметр lpCommandLine может иметь значение NULL либо указывать на строку параметров запуска приложения. Если это потребуется, приложение может извлечь адрес строки параметров через параметы функции WinMain, либо при помощи функции GetCommandLine, не имеющей параметров. Последняя возвращает адрес искомой строки. Вы можете также передать через параметр lpApplicationName значение NULL, указав адрес строки пути к программному файлу через параметр lpCommandLine. В этом случае можно передать параметры процессу, добавив их в этой строке к пути файла через пробел. Таким образом, в параметре lpCommandLine можно указать адрес командной строки для запуска процесса. lpProcessAttributeslpThreadAttributesПараметры lpProcessAttributes и lpThreadAttributes указывают атрибуты защиты, соответвтвенно, процесса и его главной задачи, которая получает управление при запуске процесса. В наших примерах мы будем указывать оба этих параметра как NULL, используя значения атрибутов защиты, принятые по умолчанию. bInheritHandlesФлаг наследования идентификатора процесса и задачи bInheritHandles определяет, как это видно из названия, возможность использования данных идентификаторов в порожденных процессах и задачах. Если такая возможность вам необходима, указите для этого параметра значение TRUE. В наших приложениях мы будем указывать значение FALSE, отменяющее наследование. dwCreationFlagsРассмотрим теперь параметр dwCreationFlags. Этот параметр определяет способ, которым будет запущен процесс, а также класс приоритета процесса. Соответственно, для параметра dwCreationFlags можно использовать флаги создания процесса, объединяя их между собой оператором логического ИЛИ, а также с одним из значений, определяющих класс приоритета процесса. Флаги создания процесса перечислены ниже: · CREATE_SUSPENDED Сразу после создания процесса его главная задача будет находиться в приостановленном состоянии. Работу этой задачи можно возобновить при помощи функции ResumeThread XE "ResumeThread" . Этот флаг может быть использован при отладке процесса. · DEBUG_PROCESS Флаг DEBUG_PROCESS используется отладчиками, которые создают процесс для отладки. Если указан этот флаг, родительский процесс (то есть отладчик) информируется о различных событиях, возникающих в отлаживаемом процессе. · DEBUG_ONLY_THIS_PROCESS Аналогично предыдущему, однако отладчик извещается о тех событиях, которые происходят только в отлаживаемом процессе, но не в процессах, запущенных отлаживаемым процессом. · CREATE_UNICODE_ENVIRONMENT Этот флаг используется в том случае, если для блока среды процесса, адрес которого передается через параметр lpEnvironment, используется кодировка Unicode. В противном случае предполагается, что для блока среды используются символы в коде ANSI. Рассмотрение кодировки Unicode выходит за рамки этой книги, однако мы, возможно, расскажем вам о ней в одной из следующих наших книг, посвященных операционной системе Microsoft Windows NT. · CREATE_NEW_CONSOLE Используется для консольных процессов. Если указан флаг CREATE_NEW_CONSOLE, для нового процесса создается новая консоль. Консольные процессы мы не будем пока рассматривать для экономии места в книге. Этот флаг несовместим с флагом DETACHED_PROCESS. · DETACHED_PROCESS Используется для консольных процессов. Если указан этот флаг, новый консольный процесс не имеет доступа к родительской консоли. При необходимости он может создать новую консоль. Этот флаг несовместим с флагом CREATE_NEW_CONSOLE. · CREATE_NEW_PROCESS_GROUP Используется для консольных процессов. Новый процесс будет корневым для группы процессов. · CREATE_SEPARATE_WOW_VDM Используется для запуска 16-разрядных приложоений Microsoft Windows. Если установлен флаг CREATE_SEPARATE_WOW_VDM, для работы приложения создается отдельная виртуальная машина DOS. Если произойдет ошибка в этом приложении, то она не скажется на работе остальных 16-разрядных приложений Microsoft Windows, работающих на других виртуальных машинах (так как последние находятся в другом адресном пространстве). · CREATE_DEFAULT_ERROR_MODE Новый процесс не наследует режим обработки ошибок, установленный родительским процессом при помощи функции SetErrorMode, и должен устанавливать этот режим самостоятельно. · REALTIME_PRIORITY_CLASS · HIGH_PRIORITY_CLASS · NORMAL_PRIORITY_CLASS · IDLE_PRIORITY_CLASS Приведенные выше четыре флага указывают класс приоритета нового процесса. Обычно вы должны использовать значение NORMAL_PRIORITY_CLASS XE "NORMAL_PRIORITY_CLASS" . lpEnvironmentНаряду с регистрационной базой данных, в которой приложения могут хранить необходимые им для выполнения программы, операционная система Microsoft Windows NT сохранила такой атавизм MS-DOS, как среда выполнения программ (очевидно, сохранила для обратной совместимости с этой операционной системой). В MS-DOS переменные среды устанавливались при помощи команд в файле autoexec.bat. Операционная система Microsoft Windows NT версии 3.51 позволяет это сделать через приложение Control Panel. Если дочерний процесс должен использовать родительский блок среды выполнения, через параметр lpEnvironment необходимо передать значение NULL. Родительский процесс может также подготовить новый блок среды, состоящий из расположенных друг за другом символьных строк, закрытых двоичным нулем. Последняя из этих строк должна быть закрыта двумя двоичными нулями. При необходимости процесс может получить адрес блока среды при помощи функции GetEnvironmentStrings, не имеющей параметров. Функция GetEnvironmentVariable позовляет узнать значение отдельных переменных блока среды. Описание этой функции вы найдете в SDK. lpCurrentDirectoryПараметр lpCurrentDirectory задает путь к символьной строке, закрытой двоичным нулем, содержащей путь к каталогу, который будет использован как рабочий при запуске процесса. Если указать этот параметр как NULL, в качестве рабочего для нового процесса будет использован рабочий каталог родительского процесса. lpStartupInfoЧерез параметр lpStartupInfo вы должны передать функции CreateProcess XE "CreateProcess" указатель на структуру типа STARTUPINFO, определяющую внешний вид окна, создаваемого для процесса: typedef struct _STARTUPINFO { DWORD cb; // размер структуры в байтах LPTSTR lpReserved; // зарезервировано LPTSTR lpDesktop; // рабочий стол и станция для процесса LPTSTR lpTitle; // заголовок окна консольного процесса DWORD dwX; // координата угла окна в пикселах DWORD dwY; // координата угла окна в пикселах DWORD dwXSize; // ширина окна в пикселах DWORD dwYSize; // высота окна в пикселах DWORD dwXCountChars; // ширина консольного окна DWORD dwYCountChars; // высота консольного окна DWORD dwFillAttribute; // атрибуты текста консольного окна DWORD dwFlags; // заполненные поля структуры WORD wShowWindow; // размеры окна по умолчанию WORD cbReserved2; // зарезервировано LPBYTE lpReserved2; // зарезервировано HANDLE hStdInput; // консольный буфер ввода HANDLE hStdOutput; // консольный буфер вывода HANDLE hStdError; // консольный буфер вывода сообщений // об ошибках } STARTUPINFO, *LPSTARTUPINFO; Несмотря на внушительный размер этой структуры, ее заполнение не вызовет у вас особых трудностей, так как большинство полей можно не использовать. cbПоле cb должно содержать размер структуры STARTUPINFO в байтах. dwFlagsПоле dwFlags содержит флаги, определяющие, содержимое каких полей структуры STARTUPINFO необходимо учитывать при запуске нового процесса, а также три дополнительных флага:
Дополнительными являются флаги STARTF_FORCEONFEEDBACK, STARTF_FORCEOFFFEEDBACK и STARTF_SCREENSAVER. Использование первого из этих флагов приводит к тому что при запуске приложения курсор мыши принимает форму песочных часов со стрелкой. При этом пользователь может работать с другими приложениями, зная, что процесс запуска данного приложения еще не завершен. Как только приложение будет запущено и станет активным, курсор примет свою обычную форму. Если же указан флаг STARTF_FORCEOFFFEEDBACK, в процессе запуска приложения курсор имеет обычную форму. Флаг STARTF_SCREENSAVER используется для создания приложений, предохраняющих экран монитора от преждеверменного выгорания. Этот флаг вызывает снижение класса приоритета после запуска до IDLE_PRIORITY_CLASS XE "IDLE_PRIORITY_CLASS" , несмотря на то что при инициализации класс приоритета был NORMAL_PRIORITY_CLASS XE "NORMAL_PRIORITY_CLASS" . Если пользователь активизирует окно такого приложения, его класс приоритета автоматически повышается. lpDesktopПоле lpDesktop используется для выбора рабочего стола и рабочей станции, где будет запущен процесс. Если вы собираетесь использовать текущий рабочий стол и текущую рабочую станцию, укажите в этом поле значение NULL. lpTitleДля консольного процесса (и только для него) вы можете указать заголовок окна в поле lpTitle. Если же в этом поле задать значение NULL, для заголовка будет использовано имя файла. dwXdwYПоля dwX и dwY определяют, соответственно, координаты X и Y левого верхнего угла окна графического приложения в пикселах. Эти значения используются для позиционирования главного окна приложения только в том случае, если при создании окна функцией CreateWindow расположение окна было указано как CW_USEDEFAULT XE "CW_USEDEFAULT" . dwXSizedwYSizeАналогично, поля dwXSize и dwYSize определяют, соответственно, ширину и высоту окна графического приложения в пикселах. Эти значения используются в том случае, если при создании окна функцией CreateWindow размыры окна были указаны как CW_USEDEFAULT XE "CW_USEDEFAULT" . dwXCountCharsdwYCountCharsПоля dwXCountChars и dwYCountChars задают, соответственно, ширину и высоту окна консольного приложения в символах. dwFillAttributeСодержимое поля dwFillAttribute задает цвет текста и фона для окна консольного приложнения. wShowWindowПоле wShowWindow определяет значение по умолчанию, которое будет использовано при первом вызове функции ShowWindow для главного окна приложения. Остановимся на этом подробнее. Как вы, наверное, помните, в приложениях Microsoft Windows версии 3.1 функция WinMain получала параметр nCmdShow, определяющий, в каком виде должно отображаться окно - в нормальном, минимизированном, максимизированном и так далее. В среде Microsoft Windows NT параметр nCmdShow функции WinMain всегда имеет значение SW_SHOWDEFAULT XE "SW_SHOWDEFAULT" . В этом случае для определения внешнего вида главного окна прилоджения используется содержимое поля wShowWindow структуры STARTUPINFO XE "STARTUPINFO" . Здесь, а также в качестве параметров функции ShowWindow, вы можете использовать следующие значения:
Вернемся к полям структуры STARTUPINFO. hStdInputhStdOutputhStdErrorПоля hStdInput, hStdOutput и hStdError определяют идентификаторы буферов, которые используются консольными приложениями, соответственно, для ввода, вывода обычной информации и вывода сообщений об ошибках. lpProcessInformationПеред вызовом функции CreateProcess вы должны передать ей через параметр lpProcessInformation адрес структуры типа PROCESS_INFORMATION XE "PROCESS_INFORMATION" , в которую будут записаны идентификаторы и системные номера созданного процесса и его главной задачи: typedef struct _PROCESS_INFORMATION { HANDLE hProcess; // идентификатор процесса HANDLE hThread; // идентификатор главной задачи процесса DWORD dwProcessId; // системный номер процесса DWORD dwThreadId; // системный номер главной задачи // процесса } PROCESS_INFORMATION; Пользуясь идентификаторами, полученными из полей hProcess и hThread, родительский процесс может управлять порожденным процессом и его главной задачей, например, изменяя класс приоритета процесса или относительный приоритет его главной задачи. Важно отметить, что после использования родительский процесс обязан закрыть полученные идентификаторы порожденного процесса и задачи при помощи функции CloseHandle XE "CloseHandle" . |