Функция CreateProcessA (processthreadsapi.h)
Создает новый процесс и его основной поток. Новый процесс выполняется в контексте безопасности вызывающего процесса.
Если вызывающий процесс олицетворяет другого пользователя, новый процесс использует маркер для вызывающего процесса, а не токен олицетворения. Чтобы запустить новый процесс в контексте безопасности пользователя, представленного маркером олицетворения, используйте функцию CreateProcessAsUser или CreateProcessWithLogonW .
Синтаксис
BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
Параметры
[in, optional] lpApplicationName
Имя выполняемого модуля. Этот модуль может быть приложением на основе Windows. Это может быть другой тип модуля (например, MS-DOS или OS/2), если соответствующая подсистема доступна на локальном компьютере.
В строке можно указать полный путь и имя файла модуля для выполнения или указать частичное имя. В случае частичного имени функция использует текущий диск и текущий каталог для завершения спецификации. Функция не будет использовать путь поиска. Этот параметр должен включать расширение имени файла; расширение по умолчанию не предполагается.
Параметр lpApplicationName может иметь значение NULL. В этом случае имя модуля должно быть первым маркером с разделителями пробелами в строке lpCommandLine . Если вы используете длинное имя файла, содержащее пробел, используйте строки в кавычках, чтобы указать, где заканчивается имя файла и начинаются аргументы; В противном случае имя файла будет неоднозначным. Например, рассмотрим строку "c:\program files\sub dir\program name". Эту строку можно интерпретировать несколькими способами. Система пытается интерпретировать возможности в следующем порядке:
- c:\program.exe
- c:\program files\sub.exe
- c:\program files\sub dir\program.exe
- c:\program files\sub dir\program name.exe
Если исполняемый модуль является 16-разрядным приложением, lpApplicationName должно иметь значение NULL, а строка, на которую указывает lpCommandLine , должна указывать исполняемый модуль и его аргументы.
Чтобы запустить пакетный файл, необходимо запустить интерпретатор команд; Задайте для параметра lpApplicationName значение cmd.exe и задайте для lpCommandLine следующие аргументы: /c плюс имя пакетного файла.
Важно!
Команда инженеров MSRC не рекомендует это. Дополнительные сведения см. в статье MS14-019 — исправление двоичного перехвата с помощью .cmd или .bat файла .
[in, out, optional] lpCommandLine
Командная строка, выполняемая.
Максимальная длина этой строки составляет 32 767 символов, включая завершающий символ NULL в Юникоде. Если lpApplicationName имеет значение NULL, часть имени модуля lpCommandLine ограничена MAX_PATH символами.
Версия этой функции в Юникоде CreateProcessW может изменять содержимое этой строки. Поэтому этот параметр не может быть указателем на память, доступную только для чтения (например , переменную const или строку литерала). Если этот параметр является строкой константы, функция может вызвать нарушение доступа.
Параметр lpCommandLine может иметь значение NULL. В этом случае функция использует строку, на которую указывает lpApplicationName , в качестве командной строки.
Если и lpApplicationName , и lpCommandLine имеют значение, отличное от NULL, строка, завершающаяся значением NULL, на которую указывает lpApplicationName , указывает модуль для выполнения, а строка, завершающаяся значением NULL, на которую указывает lpCommandLine , указывает командную строку. Новый процесс может использовать GetCommandLine для получения всей командной строки. Консольные процессы, написанные на языке C, могут использовать аргументы argc и argv для анализа командной строки. Так как argv[0] — это имя модуля, программисты C обычно повторяют имя модуля в качестве первого маркера в командной строке.
Если lpApplicationName имеет значение NULL, первый маркер командной строки с разделителями пробелами указывает имя модуля. Если вы используете длинное имя файла, содержащее пробел, используйте строки в кавычках, чтобы указать, где заканчивается имя файла и начинаются аргументы (см. описание параметра lpApplicationName ). Если имя файла не содержит расширения, добавляется .exe. Поэтому, если расширение имени файла .com, этот параметр должен включать расширение .com. Если имя файла заканчивается точкой (.) без расширения или если имя файла содержит путь, .exe не добавляется. Если имя файла не содержит пути к каталогу, система выполняет поиск исполняемого файла в следующей последовательности:
- Каталог, из которого загружено приложение.
- Текущий каталог для родительского процесса.
- 32-разрядный системный каталог Windows. Используйте функцию GetSystemDirectory , чтобы получить путь к этому каталогу.
- 16-разрядный системный каталог Windows. Нет функции, которая получает путь к этому каталогу, но выполняется поиск. Имя этого каталога — System.
- Каталог Windows. Используйте функцию GetWindowsDirectory , чтобы получить путь к этому каталогу.
- Каталоги, перечисленные в переменной среды PATH. Обратите внимание, что эта функция не выполняет поиск по пути для каждого приложения, указанному в разделе реестра Пути приложений . Чтобы включить этот путь для каждого приложения в последовательность поиска, используйте функцию ShellExecute .
[in, optional] lpProcessAttributes
Указатель на структуру SECURITY_ATTRIBUTES , которая определяет, может ли возвращенный дескриптор нового объекта процесса наследоваться дочерними процессами. Если lpProcessAttributes имеет значение NULL, дескриптор не может быть унаследован.
Элемент lpSecurityDescriptor структуры задает дескриптор безопасности для нового процесса. Если lpProcessAttributes имеет значение NULL или lpSecurityDescriptor имеет значение NULL, процесс получает дескриптор безопасности по умолчанию. Списки управления доступом в дескрипторе безопасности по умолчанию для процесса поступают из основного маркера создателя. Windows XP: Списки управления доступом в дескрипторе безопасности по умолчанию для процесса поступают из основного маркера или токена олицетворения создателя. Это поведение изменилось в Windows XP с пакетом обновления 2 (SP2) и Windows Server 2003.
[in, optional] lpThreadAttributes
Указатель на структуру SECURITY_ATTRIBUTES , которая определяет, может ли возвращенный дескриптор нового объекта потока наследоваться дочерними процессами. Если lpThreadAttributes имеет значение NULL, дескриптор не может быть унаследован.
Элемент lpSecurityDescriptor структуры задает дескриптор безопасности для основного потока. Если lpThreadAttributes имеет значение NULL или lpSecurityDescriptor имеет значение NULL, поток получает дескриптор безопасности по умолчанию. Списки управления доступом в дескрипторе безопасности по умолчанию для потока поступают из маркера процесса. Windows XP: Списки управления доступом в дескрипторе безопасности по умолчанию для потока поступают из основного маркера или маркера олицетворения создателя. Это поведение изменилось в Windows XP с пакетом обновления 2 (SP2) и Windows Server 2003.
[in] bInheritHandles
Если этот параметр имеет значение TRUE, каждый наследуемый дескриптор в вызывающем процессе наследуется новым процессом. Если параметр имеет значение FALSE, дескрипторы не наследуются. Обратите внимание, что унаследованные дескрипторы имеют те же значения и права доступа, что и исходные дескрипторы. Дополнительные сведения о наследуемых дескрипторах см. в разделе Примечания.
Службы терминалов: Нельзя наследовать дескрипторы между сеансами. Кроме того, если этот параметр имеет значение TRUE, процесс необходимо создать в том же сеансе, что и вызывающий объект.
Процессы Защищенного процесса Light (PPL): Наследование универсального дескриптора блокируется, когда процесс PPL создает процесс, отличный от PPL, так как PROCESS_DUP_HANDLE не допускается из процесса, отличного от PPL, к процессу PPL. См. раздел Управление правами на доступ и безопасность процесса.
Windows 7: STD_INPUT_HANDLE, STD_OUTPUT_HANDLE и STD_ERROR_HANDLE наследуются, даже если параметр имеет значение FALSE.
[in] dwCreationFlags
Флаги, управляющие классом приоритета и созданием процесса. Список значений см. в разделе Флаги создания процесса.
Этот параметр также управляет классом приоритета нового процесса, который используется для определения приоритетов планирования потоков процесса. Список значений см. в разделе GetPriorityClass. Если ни один из флагов класса приоритета не указан, класс приоритета по умолчанию NORMAL_PRIORITY_CLASS , если только класс приоритета процесса создания не IDLE_PRIORITY_CLASS или BELOW_NORMAL_PRIORITY_CLASS. В этом случае дочерний процесс получает класс приоритета по умолчанию вызывающего процесса.
Если параметр dwCreationFlags имеет значение 0:
- Процесс наследует режим ошибок вызывающего объекта и родительской консоли.
- Предполагается, что блок среды для нового процесса содержит символы ANSI (дополнительные сведения см. в разделе параметр lpEnvironment ).
- 16-разрядное приложение windows выполняется на общей виртуальной машине DOS (VDM).
[in, optional] lpEnvironment
Указатель на блок среды для нового процесса. Если этот параметр имеет значение NULL, новый процесс использует среду вызывающего процесса.
Блок среды состоит из блока строк, завершаемых значением NULL. Каждая строка имеет следующий вид:
Имя=значение\0
Поскольку знак равенства используется в качестве разделителя, его нельзя использовать в имени переменной среды.
Блок среды может содержать символы Юникода или ANSI. Если блок среды, на который указывает lpEnvironment , содержит символы Юникода, убедитесь, что dwCreationFlags содержит CREATE_UNICODE_ENVIRONMENT.
Версия ANSI этой функции CreateProcessA завершается ошибкой, если общий размер блока среды для процесса превышает 32 767 символов.
Обратите внимание, что блок среды ANSI завершается двумя нулевыми байтами: один для последней строки, еще один для завершения блока. Блок среды Юникод завершается четырьмя нулевыми байтами: два для последней строки, еще два для завершения блока.
[in, optional] lpCurrentDirectory
Полный путь к текущему каталогу для процесса. Строка также может указывать UNC-путь.
Если этот параметр имеет значение NULL, новый процесс будет иметь тот же текущий диск и каталог, что и вызывающий процесс. (Эта функция предоставляется в основном для оболочек, которым необходимо запустить приложение и указать его начальный диск и рабочий каталог.)
[in] lpStartupInfo
Указатель на структуру STARTUPINFO или STARTUPINFOEX .
Чтобы задать расширенные атрибуты, используйте структуру STARTUPINFOEX и укажите EXTENDED_STARTUPINFO_PRESENT в параметре dwCreationFlags .
Дескрипторы в STARTUPINFO или STARTUPINFOEX должны закрываться с помощью CloseHandle , если они больше не нужны.
Важно!
Вызывающий объект отвечает за то, чтобы стандартные поля дескрипторов в STARTUPINFO содержали допустимые значения дескрипторов. Эти поля копируются без изменений в дочерний процесс без проверки, даже если элемент dwFlags указывает STARTF_USESTDHANDLES. Неправильные значения могут привести к неправильному работе или сбою дочернего процесса. Используйте средство проверки среды выполнения Проверки приложений для обнаружения недопустимых дескрипторов.
[out] lpProcessInformation
Указатель на структуру PROCESS_INFORMATION , которая получает идентификационные сведения о новом процессе.
Маркеры в PROCESS_INFORMATION должны быть закрыты с помощью CloseHandle , если они больше не нужны.
Возвращаемое значение
Если функция выполняется успешно, возвращается ненулевое значение.
Если функция выполняется неудачно, возвращается нулевое значение. Дополнительные сведения об ошибке можно получить, вызвав GetLastError.
Обратите внимание, что функция возвращается до завершения инициализации процесса. Если не удается найти необходимую библиотеку DLL или не удается инициализировать, процесс завершается. Чтобы получить состояние завершения процесса, вызовите Метод GetExitCodeProcess.
Комментарии
Процессу назначается идентификатор процесса. Идентификатор действителен до завершения процесса. Его можно использовать для идентификации процесса или указать в функции OpenProcess , чтобы открыть дескриптор процесса. Начальному потоку в процессе также назначается идентификатор потока. Его можно указать в функции OpenThread , чтобы открыть дескриптор потока. Идентификатор действителен до завершения потока и может использоваться для уникальной идентификации потока в системе. Эти идентификаторы возвращаются в структуре PROCESS_INFORMATION .
Имя исполняемого файла в командной строке, которое операционная система предоставляет процессу, не обязательно совпадает с именем в командной строке, которую вызывающий процесс присваивает функции CreateProcess . Операционная система может добавить полный путь к имени исполняемого файла, которое предоставляется без полного пути.
Вызывающий поток может использовать функцию WaitForInputIdle , чтобы дождаться завершения инициализации нового процесса и ожидать ввода данных пользователем без ожидания ввода. Это может быть полезно для синхронизации между родительским и дочерним процессами, так как CreateProcess возвращает , не дожидаясь завершения инициализации нового процесса. Например, процесс создания будет использовать WaitForInputIdle перед попыткой найти окно, связанное с новым процессом.
Предпочтительным способом завершения процесса является использование функции ExitProcess , так как эта функция отправляет уведомление о приближении завершения во все библиотеки DLL, присоединенные к процессу. Другие средства завершения процесса не уведомляют подключенные библиотеки DLL. Обратите внимание, что когда поток вызывает ExitProcess, другие потоки процесса завершаются без возможности выполнения дополнительного кода (включая код завершения потока присоединенных библиотек DLL). Дополнительные сведения см. в разделе Прекращение процесса.
Родительский процесс может напрямую изменять переменные среды дочернего процесса во время создания процесса. Это единственная ситуация, когда процесс может напрямую изменять параметры среды другого процесса. Дополнительные сведения см. в разделе Изменение переменных среды.
Если приложение предоставляет блок среды, сведения о текущем каталоге системных дисков не распространяются автоматически в новый процесс. Например, существует переменная среды с именем =C: значением является текущий каталог на диске C. Приложение должно вручную передать сведения о текущем каталоге в новый процесс. Для этого приложение должно явно создать эти строки переменных среды, отсортировать их по алфавиту (так как система использует отсортированную среду) и поместить их в блок среды. Как правило, они выполняются в передней части блока среды из-за порядка сортировки блоков среды.
Одним из способов получения сведений о текущем каталоге для диска X является выполнение следующего вызова: GetFullPathName("X:", ...)
. Это позволяет избежать того, чтобы приложение проверялось в блоке среды. Если возвращается полный путь X:, нет необходимости передавать это значение в качестве данных среды, так как корневой каталог является текущим каталогом по умолчанию для диска X нового процесса.
При создании процесса с указанным CREATE_NEW_PROCESS_GROUP выполняется неявный вызов SetConsoleCtrlHandler(NULL,TRUE) от имени нового процесса; это означает, что для нового процесса отключено сочетание клавиш CTRL+C. Это позволяет оболочкам самостоятельно обрабатывать клавиши CTRL+C и выборочно передавать этот сигнал в вложенные процессы. Сочетание клавиш CTRL+BREAK не отключено и может использоваться для прерывания процесса или группы процессов.
По умолчанию передача TRUE в качестве значения параметра bInheritHandles приводит к тому, что все наследуемые дескрипторы наследуются новым процессом. Это может быть проблематично для приложений, которые создают процессы из нескольких потоков одновременно, но хотят, чтобы каждый процесс наследовал разные дескрипторы. Приложения могут использовать функцию UpdateProcThreadAttributeList с параметром PROC_THREAD_ATTRIBUTE_HANDLE_LIST для предоставления списка дескрипторов, наследуемых определенным процессом.
Примечания по безопасности
Первый параметр , lpApplicationName, может иметь значение NULL. В этом случае имя исполняемого файла должно находиться в строке с разделителями пробелами, на которую указывает lpCommandLine. Если в имени исполняемого файла или пути есть пробел, существует риск запуска другого исполняемого файла из-за того, как функция анализирует пробелы. Следующий пример опасен тем, что функция попытается запустить "Program.exe", если она существует, а не "MyApp.exe". LPTSTR szCmdline = _tcsdup(TEXT("C:\\Program Files\\MyApp -L -S"));
CreateProcess(NULL, szCmdline, /* ... */);
Если злоумышленник создает в системе приложение с именем "Program.exe", любая программа, которая неправильно вызывает CreateProcess с помощью каталога Program Files, запустит это приложение вместо предполагаемого приложения.
Чтобы избежать этой проблемы, не передайте значение NULL для lpApplicationName. Если для lpApplicationNameзадано значение NULL, используйте в lpCommandLine путь к исполняемому файлу в кавычках, как показано в примере ниже.
LPTSTR szCmdline[] = _tcsdup(TEXT("\"C:\\Program Files\\MyApp\" -L -S"));
CreateProcess(NULL, szCmdline, /*...*/);
Примеры
Пример см. в разделе Создание процессов.
Примечание
Заголовок processthreadsapi.h определяет CreateProcess в качестве псевдонима, который автоматически выбирает версию ANSI или Юникод этой функции на основе определения константы препроцессора ЮНИКОД. Использование псевдонима, не зависящий от кодирования, с кодом, который не является нейтральным для кодировки, может привести к несоответствиям, которые приводят к ошибкам компиляции или времени выполнения. Дополнительные сведения см. в разделе Соглашения для прототипов функций.
Требования
Требование | Значение |
---|---|
Минимальная версия клиента | Windows XP [классические приложения | Приложения UWP] |
Минимальная версия сервера | Windows Server 2003 [классические приложения | Приложения UWP] |
Целевая платформа | Windows |
Header | processthreadsapi.h (включая Windows.h в Windows Server 2003, Windows Vista, Windows 7, Windows Server 2008 Windows Server 2008 R2) |
Библиотека | Kernel32.lib |
DLL | Kernel32.dll |