CreateProcessAsUser

【勇芳软件工作室】汉化HomePreviousNext

CreateProcessAsUser函数创建一个新进程及其主线程。然后,新进程执行指定的可执行文件。CreateProcessAsUser功能类似于CreateProcess功能,但新进程在由【hToken】参数表示的用户的安全上下文中运行。默认情况下,新进程是非交互式的,即它运行在不可见的桌面上,无法接收用户输入。此外,默认情况下,新进程继承调用进程的环境,而不是与指定用户关联的环境。

BOOL CreateProcessAsUser(

HANDLE 【hToken】,//处理表示已登录用户的令牌
LPCTSTR 【lpApplicationName】,//指向可执行模块名称的指针
LPTSTR 【lpCommandLine】,//指向命令行字符串的指针
LPSECURITY_ATTRIBUTES 【lpProcessAttributes】,//指向进程安全属性的指针
LPSECURITY_ATTRIBUTES 【lpThreadAttributes】,//指向线程安全属性的指针
BOOL 【bInheritHandles】,//新进程继承句柄
DWORD 【dwCreationFlags】,//创建标志
LPVOID 【// pointer to new environment block】,//指向新的环境块
LPCTSTR 【lpCurrentDirectory】,//指向当前目录名称的指针
LPSTARTUPINFO 【lpStartupInfo】,//指向STARTUPINFO的指针
LPPROCESS_INFORMATION 【lpProcessInformation】//指向PROCESS_INFORMATION的指针
); 

参数

【hToken】

处理代表用户的主令牌。由令牌表示的用户必须具有对由【lpApplicationName】【lpCommandLine】参数指定的应用程序的读取和执行访问权限。

如果您的进程具有SE_TCB_NAME特权,则可以调用LogonUser函数获取代表指定用户的主令牌。

或者,您可以调用DuplicateTokenEx函数将模拟令牌转换为主令牌。这允许正在冒充客户机的服务器应用程序创建具有客户机安全上下文的进程。

CreateProcessAsUser函数的其他参数的行为就像CreateProcess函数的类似参数。

【lpApplicationName】

指向以null结尾的字符串,指定要执行的模块的完整路径和文件名。如果指定了部分名称,则默认使用当前驱动器和当前目录。如果此参数为NULL,则模块名称必须是【lpCommandLine】字符串中第一个以空格分隔的空白符号。指定的模块可以是基于Win32的应用程序,或者如果本地计算机上有适当的子系统可用,它可以是其他类型的模块(例如,MS-DOS或OS / 2)。

【lpCommandLine】

指向以空值终止的字符串,指定要执行的应用程序的命令行。如果此参数为NULL,则使用【lpApplicationName】字符串作为命令行。如果【lpApplicationName】【lpCommandLine】都不为空,则【lpApplicationName】指定要执行的模块,并且【lpCommandLine】用作命令行。新进程可以使用GetCommandLine检索整个命令行;或C运行时进程可以使用ARGC / ARGV机制。

如果【lpApplicationName】为NULL,则命令行的第一个以空格为空的分隔符号将指定模块名称。如果文件名不包含扩展名,则假定为.EXE。如果文件名以不带扩展名的句点(。)结尾,或者文件名包含路径,则不附加.EXE。如果文件名不包含目录路径,Windows将按以下顺序搜索可执行文件:

1.应用程序加载的目录。

2.当前目录。

3.32位Windows系统目录。使用GetSystemDirectory函数获取此目录的路径。该目录的名称是SYSTEM32。

4.16位Windows系统目录。没有获取此目录的路径的Win32函数,但它被搜索。该目录的名称是SYSTEM。

5. Windows目录。使用GetWindowsDirectory函数获取此目录的路径。

6. PATH环境变量中列出的目录。

如果要创建的进程是基于MS-DOS或16位Windows的应用程序,则【lpCommandLine】应该是一个完整的命令行,其中第一个元素是应用程序名称。因为这也适用于基于Win32的应用程序,它是设置【lpCommandLine】的最强大的方法。

【lpProcessAttributes】

指向SECURITY_ATTRIBUTES结构的指针,指定新进程的安全描述符,并确定子进程是否可以继承返回的句柄。如果【lpProcessAttributes】为NULL,则该进程将获得默认安全描述符,并且该句柄不能被继承。

【lpThreadAttributes】

指向SECURITY_ATTRIBUTES结构的指针,该结构指定新进程的安全描述符,并确定子进程是否可以继承返回的句柄。如果【lpThreadAttributes】为NULL,线程将获得默认的安全描述符,并且句柄不能被继承。

【bInheritHandles】

指示新进程是否继承来自调用进程的句柄。如果为TRUE,则调用进程中的每个可继承的打开句柄都由新进程继承。继承的句柄具有与原始句柄相同的值和访问权限。

【dwCreationFlags】

指定控制优先级类和进程创建的附加标志。可以以任何组合指定以下创建标志,除非另有说明:

含义
CREATE_DEFAULT_ERROR_MODE 
 新的进程不会继承调用进程的错误模式。相反,CreateProcessAsUser给新进程当前的默认错误模式。应用程序通过调用SetErrorMode来设置当前的默认错误模式。

此标志对于禁用硬错误运行的多线程shell应用程序特别有用。

CreateProcessAsUser的默认行为是新进程继承调用者的错误模式。设置此标志会更改该默认行为。

CREATE_NEW_CONSOLE 
 新进程有一个新的控制台,而不是继承父控制台。该标志不能与DETACHED_PROCESS标志一起使用。
CREATE_NEW_PROCESS_GROUP 
 新进程是新进程组的根进程。进程组包括作为此根进程的后代的所有进程。新进程组的进程标识符与【lpProcessInformation】参数中返回的进程标识符相同。GenerateConsoleCtrlEvent功能使用进程组,以将CTRL + C或CTRL + BREAK信号发送到一组控制台进程。
CREATE_SEPARATE_WOW_VDM 
 该标志仅在启动16位Windows程序时有效。如果设置,新工艺是在私人DOS虚拟机(VDM)中运行。默认情况下,所有16位Windows程序都运行在一个共享的VDM中。单独运行的优点是崩溃只能杀死单个VDM;在不同VDM中运行的任何其他程序继续正常运行。而且,在单独VDM中运行的16位Windows应用程序具有单独的输入队列。这意味着如果一个应用程序暂时挂起,单独VDM中的应用程序将继续接收输入。
CREATE_SUSPENDED 
 新进程的主线程将以暂停状态创建,直到ResumeThread函数被调用才会运行。
CREATE_UNICODE_ENVIRONMENT 
 如果设置,【// pointer to new environment block】指向的环境块使用Unicode字符。如果清除,则环境块使用ANSI字符。
DEBUG_PROCESS 
 如果设置,则调用进程被视为调试器,并且新进程是被调试的进程。系统通知调试器在被调试过程中发生的所有调试事件。
DEBUG_ONLY_THIS_PROCESS 
 如果未设置并调用调用进程,则新进程将成为调用进程调试器调试的另一进程。如果调用进程不是正在调试的进程,则不会发生与调试相关的操作。
DETACHED_PROCESS 
 对于控制台进程,新进程无法访问父进程的控制台。新进程可以稍后调用AllocConsole函数来创建一个新的控制台。该标志不能与CREATE_NEW_CONSOLE标志一起使用。

【dwCreationFlags】参数还控制新进程的优先级,用于确定进程线程的调度优先级。如果没有指定以下优先级标志,优先级类默认为NORMAL_PRIORITY_CLASS,除非创建过程的优先级为IDLE_PRIORITY_CLASS.在这种情况下,子进程的默认优先级类为IDLE_PRIORITY_CLASS.可以指定以下标志之一:

优先含义
HIGH_PRIORITY_CLASS表示执行必须立即执行以执行正确运行的时间关键任务的进程。高优先级类进程的线程抢占正常优先级或空闲优先级进程的线程。一个例子是Windows任务列表,无论操作系统上的负载如何,Windows任务列表在用户调用时都必须快速响应。使用高优先级类时要格外小心,因为高优先级的CPU绑定应用程序可以使用几乎所有可用的周期。
IDLE_PRIORITY_CLASS表示一个进程,其线程仅在系统空闲时运行,并被任何在较高优先级类中运行的进程的线程抢占。一个例子是屏幕保护程序。空闲优先级类由子进程继承。
NORMAL_PRIORITY_CLASS表示没有特殊调度需要的正常进程。
REALTIME_PRIORITY_CLASS表示具有最高可能优先级的进程。实时优先级进程的线程抢占所有其他进程的线程,包括执行重要任务的操作系统进程。例如,执行超过非常短的间隔的实时进程可能导致磁盘缓存不会刷新或导致鼠标无响应。

【// pointer to new environment block】

指向新进程的环境块。如果此参数为NULL,则新进程将使用调用进程的环境。

一个环境块由一个以null结尾的空端字符串的块组成。每个字符串的形式如下:

name=value

因为等号用作分隔符,所以不能在环境变量的名称中使用。

如果应用程序提供环境块,而不是为此参数传递NULL,则系统驱动器的当前目录信息不会自动传播到新进程。有关这种情况的讨论以及如何处理,请参阅以下备注部分。

环境块可以包含Unicode或ANSI字符。如果【// pointer to new environment block】指向的环境块包含Unicode字符,则【dwCreationFlags】??字段的CREATE_UNICODE_ENVIRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清除。

请注意,ANSI环境块由两个零字节终止:一个用于最后一个字符串,另一个用于终止块。Unicode环境块由四个零字节终止:两个用于最后一个字符串,另外两个用于终止块。

【lpCurrentDirectory】

指向一个空值终止的字符串,指定新进程的当前驱动器和目录。字符串必须是包含驱动器盘符的完整路径和文件名。如果此参数为NULL,则使用与调用进程相同的当前驱动器和目录创建新进程。此选项主要用于需要启动应用程序并指定其初始驱动器和工作目录的shell。

【lpStartupInfo】

指向STARTUPINFO结构,指定如何显示新进程的主窗口。

【lpProcessInformation】

指向PROCESS_INFORMATION结构的接收关于新进程的标识信息。

返回值

如果函数成功,返回值不为零。

如果函数失败,返回值为零。要获取扩展错误信息,请调用GetLastError.

备注

CreateProcessAsUser功能需要SE_ASSIGNPRIMARYTOKEN_NAME和SE_INCREASE_QUOTA_NAME权限。如果它们尚未启用,CreateProcessAsUser将在呼叫期间启用它们。

默认情况下,CreateProcessAsUser在非交互式窗口站上创建新进程,其中桌面不可见,无法接收用户输入。要使用户能够与新进程进行交互,您必须在STARTUPINFO结构的lpDesktop成员中指定默认交互式窗口工作站和桌面名称“winsta0 \\ default”。另外,在调用CreateProcessAsUser之前,您必须更改默认交互式窗口站和默认桌面的自由访问控制列表(DACL)。窗口站和桌面的DACL必须授予对由【hToken】参数表示的用户的访问权限。

CreateProcessAsUser不将指定的用户配置文件加载到HKEY_USERS注册表项。这意味着访问HKEY_CURRENT_USER注册表项中的信息可能不会产生与正常交互式登录一致的结果。在致电CreateProcessAsUser之前,您有责任将用户的注册表配置单元加载到HKEY_USERS中。

如果【// pointer to new environment block】参数为NULL,则新进程将继承调用进程的环境。CreateProcessAsUser不会自动修改环境块以包含特定于【hToken】表示的用户的环境变量。例如,如果【// pointer to new environment block】为NULL,则USERNAME和USERDOMAIN变量将从调用进程继承。您有责任为新流程准备环境块,并在【// pointer to new environment block】中指定。

CreateProcessAsUser允许您在呼叫者或目标用户的安全上下文中访问指定的目录和可执行映像。默认情况下,CreateProcessAsUser访问调用者的安全上下文中的目录和可执行映像。在这种情况下,如果调用者无法访问目录和可执行映像,则该函数将失败。要使用目标用户的安全上下文访问目录和可执行映像,请在致电CreateProcessAsUser之前,在ImpersonateLoggedOnUser函数的调用中指定【hToken】.

新进程和新的线程句柄将创建具有完全访问权限(PROCESS_ALL_ACCESS和THREAD_ALL_ACCESS)。对于任一句柄,如果没有提供安全描述符,则可以在需要该类型的对象句柄的任何函数中使用句柄。当提供安全描述符时,在授予访问权限之前,对句柄的所有后续使用执行访问检查。如果访问检查拒绝访问,则请求进程不能使用句柄来访问进程或线程。

如果【lpProcessAttributes】参数为NULL,则将使用【hToken】参数中引用的用户的默认安全性描述符。此安全描述符可能不允许对呼叫者的访问,在这种情况下,一旦运行该进程可能再次被打开。PROCESS_INFORMATION结构中返回的句柄是有效的,并将继续具有所有访问权限。线程属性也是如此。

CloseHandle不再需要时,必须使用CloseHandle关闭PROCESS_INFORMATION手柄。

该进程被分配一个进程标识符。该标识符有效,直到该过程终止。它可以用于标识进程,或者在OpenProcess函数中指定以打开进程的句柄。进程中的初始线程也被分配一个线程标识符。该标识符在线程终止之前有效,可用于唯一标识系统中的线程。这些标识符在PROCESS_INFORMATION结构中返回。

【lpApplicationName】【lpCommandLine】字符串中指定应用程序名称时,应用程序名称是否包含文件扩展名无关紧要,但有一个例外:文件扩展名为基于MS-DOS或基于Windows的应用程序。 COM必须包含.COM扩展名。

调用线程可以使用WaitForInputIdle函数等待新进程完成初始化,并等待用户输入,而不输入任何输入。这对于父进程和子进程之间的同步很有用,因为CreateProcessAsUser返回而不等待新进程完成其初始化。例如,创建过程将在尝试查找与新进程关联的窗口之前使用WaitForInputIdle.

关闭进程的首选方法是使用ExitProcess函数,因为此函数通知附加到接近终止进程的所有动态链接库(DLL)。关闭进程的其他方法不通知附加的DLL。请注意,当一个线程调用ExitProcess时,进程的其他线程被终止,没有机会执行任何附加代码(包括连接的DLL的线程终止代码)。

ExitProcessExitThreadCreateThreadCreateRemoteThread,并且正在开始(作为CreateProcessAsUser的调用结果))的进程在进程之间彼此序列化。这些事件中只有一个可以一次发生。这意味着以下限制:

*在进程启动和DLL初始化例程中,可以创建新的线程,但是直到进程的DLL初始化完成为止,才能开始执行。

一个进程中只有一个线程可以在一个DLL初始化或分离例程中。

* ExitProcess函数不会返回,直到没有线程正在执行DLL初始化或分离例程。

也可以看看

AllocConsole, CloseHandle, CreateProcess, CreateRemoteThread, CreateThread, DuplicateTokenEx, ExitProcess, ExitThread, GenerateConsoleCtrlEvent, GetCommandLine, GetEnvironmentStrings, GetExitCodeProcess, GetFullPathName, GetStartupInfo, GetSystemDirectory, GetWindowsDirectory, ImpersonateLoggedOnUser, LoadModule, LogonUser, OpenProcess, PROCESS_INFORMATION, ResumeThread, SECURITY_ATTRIBUTES, SetConsoleCtrlHandler, SetErrorMode, STARTUPINFO, TerminateProcess, WaitForInputIdle, WinExec