Указание исполняемого модуля и командной строки

Для указания имени файла исполняемого модуля используются как параметр lpApplicationName, так и параметр lpCommandLine. При этом действуют следующие правила:

• Указатель lpApplicationName, если его значение не равно NULL, указывает на строку, содержащую имя файла исполняемого модуля. Если имя модуля содержит пробелы, его следует заключить в кавычки. Более детальное описание приводится ниже.

• Если же значение указателя lpApplicationName равно NULL, то имя модуля определяется первой из лексем, переданных параметром lpCommandLine.

Обычно задается только параметр lpCommandLine, в то время как параметр lpApplicationName полагается равным NULL. Тем не менее, ниже приведены более подробные правила, которые определяют порядок использования этих двух параметров.

• Параметр lpApplicationName, если он не равен NULL, определяет исполняемый модуль. В строке, на которую указывает этот указатель, задайте полный путь доступа и имя файла или же ограничьтесь только именем файла, и тогда будут использоваться текущие диск и каталог; дополнительный поиск при этом производиться не будет. В имя файла включите расширение, например, .EXE или .ВАТ.

• Если значение параметра lpApplicationName равно NULL, то именем исполняемого модуля является первая из разделенных пробельными символами лексем, переданных параметром lpCommandLine. Если имя полный путь доступа не указан, то поиск файла осуществляется в следующем порядке:

1. Каталог модуля текущего процесса.

2. Текущий каталог.

3. Системный каталог Windows, информацию о котором можно получить с помощью функции GetSystemDirectory.

4. Каталог Windows, возвращаемый функцией GetWindowsDirectory.

5. Каталоги, перечисленные в переменной окружения PATH.

Новый процесс может получить командную строку посредством обычного argv-механизма или путем вызова функции GetCommandLine для получения командной строки в виде одиночной строки символов.

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

Вовсе не обязательно, чтобы новый процесс создавался с тем же определением UNICODE, что и родительский процесс. Возможны любые комбинации. Использование _tmain, как обсуждалось в главе 2, облегчает разработку программного кода, который сможет работать как с символами Unicode, так и с символами ASCII.

Наследуемые дескрипторы

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

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

Кроме того, чтобы сделать наследуемым любой отдельный дескриптор, также требуется предпринимать специальные действия, поскольку дескрипторы не становятся таковыми по умолчанию. Создать наследуемый дескриптор можно либо путем использования структуры SECURITY_ATTRIBUTES в момент создания дескриптора, либо путем копирования существующего дескриптора.

В структуре SECURITY_ATTRIBUTES присутствует флаг bInheritHandle, значение которого должно быть установлено равным TRUE. He забывайте также о том, что элемент nLength должен инициализироваться следующим значением:

sizeof(SECURITY_ATTRIBUTES)

Приведенный ниже фрагмент кода иллюстрирует создание наследуемых файловых или иных дескрипторов в типичных случаях. В этом примере дескриптор защиты в структуре атрибутов защиты установлен в NULL; подробнее об использовании дескрипторов защиты говорится в главе 15.

HANDLE h1, h2, h3;

SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };

h1 = CreateFile(…, sa, …); /* Наследуемый. */

h2 = CreateFile(…, NULL, …); /* Ненаследуемый. */

h3 = CreateFile(…, sa, …); /* Наследуемый. Возможно повторное использование структуры sa. */

Однако дочернему процессу значение наследуемого дескриптора пока еще не известно, и поэтому родительский процесс должен передать это значение дочернему процессу либо через механизм межпроцессного взаимодействия (Interprocess Communication, IPC), либо путем назначения дескриптора стандартному устройству ввода/вывода в структуре STARTUPINFO, как это делается в первом из примеров, приведенных в данной главе (программа 6.1), а также в ряде примеров в остальной части книги. Обычно последний метод является более предпочтительным, так как он позволяет перенаправить ввод/вывод стандартным способом без внесения каких-либо изменений в дочернюю программу.

В случае дескрипторов, которые не являются дескрипторами файлов или не используются для перенаправления ввода/вывода, применим другой способ, в соответствии с которым дескриптор преобразуется в текстовый формат и помещается в командную строку или переменную окружения. Такой подход можно использовать лишь в том случае, если дескриптор является наследуемым, поскольку и родительский, и дочерний процессы используют для идентификации дескриптора одно и то же значение. Один из способов реализации этого подхода предлагается в упражнении 6.2, а соответствующее решение приводится на Web-сайте книги.

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

На рис. 6.2 показан пример двух процессов с двумя различными таблицами дескрипторов, в которых с одним и тем же файлом или иным объектом связаны два различных дескриптора. Процесс 1 является родительским, процесс 2 — дочерним. Если принадлежащий дочернему процессу дескриптор был унаследован им, как это имеет место в случае дескрипторов 1 и 3, то значения дескрипторов в обоих процессах будут одинаковыми.

Однако подобные дескрипторы могут иметь и различные значения. Так, на файл D указывают два дескриптора, причем процесс 2 получил дескриптор за счет вызова функции CreateFile, а не путем наследования. Наконец, возможны ситуации, когда один из процессов имеет дескриптор объекта, а второй — не имеет, что наблюдается для файлов В и Е. Так происходит в тех случаях, когда дескриптор создается дочерним процессом или дублируется из одного процесса в другой, о чем говорится в разделе Дублирование дескрипторов.

Рис. 6.2. Таблицы дескрипторов объектов для двух процессов

Модуль числа. Математика 6 класс.


Похожие статьи.

Понравилась статья? Поделиться с друзьями: