Vanara/PInvoke/Security/AdvApi32/ProcessThreadsApi.cs

1381 lines
96 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.InteropServices;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke
{
public static partial class AdvApi32
{
/// <summary>
/// <para>
/// Creates a new process and its primary thread. The new process runs in the security context of the user represented by the
/// specified token.
/// </para>
/// <para>
/// Typically, the process that calls the <c>CreateProcessAsUser</c> function must have the <c>SE_INCREASE_QUOTA_NAME</c> privilege
/// and may require the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege if the token is not assignable. If this function fails with
/// <c>ERROR_PRIVILEGE_NOT_HELD</c> (1314), use the CreateProcessWithLogonW function instead. <c>CreateProcessWithLogonW</c> requires
/// no special privileges, but the specified user account must be allowed to log on interactively. Generally, it is best to use
/// <c>CreateProcessWithLogonW</c> to create a process with alternate credentials.
/// </para>
/// </summary>
/// <param name="hToken">
/// <para>
/// A handle to the primary token that represents a user. The handle must have the <c>TOKEN_QUERY</c>, <c>TOKEN_DUPLICATE</c>, and
/// <c>TOKEN_ASSIGN_PRIMARY</c> access rights. For more information, see Access Rights for Access-Token Objects. The user represented
/// by the token must have read and execute access to the application specified by the lpApplicationName or the lpCommandLine parameter.
/// </para>
/// <para>
/// To get a primary token that represents the specified user, call the LogonUser function. Alternatively, you can call the
/// DuplicateTokenEx function to convert an impersonation token into a primary token. This allows a server application that is
/// impersonating a client to create a process that has the security context of the client.
/// </para>
/// <para>
/// If hToken is a restricted version of the caller's primary token, the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege is not required.
/// If the necessary privileges are not already enabled, <c>CreateProcessAsUser</c> enables them for the duration of the call. For
/// more information, see Running with Special Privileges.
/// </para>
/// <para>
/// <c>Terminal Services:</c> The process is run in the session specified in the token. By default, this is the same session that
/// called LogonUser. To change the session, use the SetTokenInformation function.
/// </para>
/// </param>
/// <param name="lpApplicationName">
/// <para>
/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
/// </para>
/// <para>
/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use
/// the search path. This parameter must include the file name extension; no default extension is assumed.
/// </para>
/// <para>
/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white spacedelimited token
/// in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the
/// file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program
/// files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities
/// in the following order:
/// </para>
/// <para>
/// <c>c:\program.exe</c><c>c:\program files\sub.exe</c><c>c:\program files\sub dir\program.exe</c><c>c:\program files\sub
/// dir\program name.exe</c> If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the
/// string pointed to by lpCommandLine should specify the executable module as well as its arguments. By default, all 16-bit
/// Windows-based applications created by <c>CreateProcessAsUser</c> are run in a separate VDM (equivalent to
/// <c>CREATE_SEPARATE_WOW_VDM</c> in CreateProcess).
/// </para>
/// </param>
/// <param name="lpCommandLine">
/// <para>
/// The command line to be executed. The maximum length of this string is 32K characters. If lpApplicationName is <c>NULL</c>, the
/// module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
/// </para>
/// <para>
/// The Unicode version of this function, <c>CreateProcessAsUserW</c>, can modify the contents of this string. Therefore, this
/// parameter cannot be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a
/// constant string, the function may cause an access violation.
/// </para>
/// <para>
/// The lpCommandLine parameter can be <c>NULL</c>. In that case, the function uses the string pointed to by lpApplicationName as the
/// command line.
/// </para>
/// <para>
/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, *lpApplicationName specifies the module to execute, and
/// *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console
/// processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C
/// programmers generally repeat the module name as the first token in the command line.
/// </para>
/// <para>
/// If lpApplicationName is <c>NULL</c>, the first white spacedelimited token of the command line specifies the module name. If you
/// are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin
/// (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended.
/// Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period
/// (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory
/// path, the system searches for the executable file in the following sequence:
/// </para>
/// <list type="number">
/// <item>
/// <term>The directory from which the application loaded.</term>
/// </item>
/// <item>
/// <term>The current directory for the parent process.</term>
/// </item>
/// <item>
/// <term>The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.</term>
/// </item>
/// <item>
/// <term>The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>
/// The directories that are listed in the PATH environment variable. Note that this function does not search the per-application
/// path specified by the <c>App Paths</c> registry key. To include this per-application path in the search sequence, use the
/// ShellExecute function.
/// </term>
/// </item>
/// </list>
/// <para>
/// The system adds a null character to the command line string to separate the file name from the arguments. This divides the
/// original string into two strings for internal processing.
/// </para>
/// </param>
/// <param name="lpProcessAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new process object and determines
/// whether child processes can inherit the returned handle to the process. If lpProcessAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor and the handle cannot be inherited.
/// The default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow
/// access for the caller, in which case the process may not be opened again after it is run. The process handle is valid and will
/// continue to have full access rights.
/// </param>
/// <param name="lpThreadAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread object and determines
/// whether child processes can inherit the returned handle to the thread. If lpThreadAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the thread gets a default security descriptor and the handle cannot be inherited. The
/// default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow access
/// for the caller.
/// </param>
/// <param name="bInheritHandles">
/// <para>
/// If this parameter is <c>TRUE</c>, each inheritable handle in the calling process is inherited by the new process. If the
/// parameter is <c>FALSE</c>, the handles are not inherited. Note that inherited handles have the same value and access rights as
/// the original handles.
/// </para>
/// <para>
/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is <c>TRUE</c>, you must
/// create the process in the same session as the caller.
/// </para>
/// <para>
/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
/// </para>
/// </param>
/// <param name="dwCreationFlags">
/// <para>
/// The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.
/// </para>
/// <para>
/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the
/// process's threads. For a list of values, see GetPriorityClass. If none of the priority class flags is specified, the priority
/// class defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
/// </para>
/// </param>
/// <param name="lpEnvironment">
/// <para>
/// A pointer to an environment block for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of
/// the calling process.
/// </para>
/// <para>An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:</para>
/// <para>name=value\0</para>
/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
/// <para>
/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and
/// the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
/// </para>
/// <para>
/// The ANSI version of this function, <c>CreateProcessAsUserA</c> fails if the total size of the environment block for the process
/// exceeds 32,767 characters.
/// </para>
/// <para>
/// Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A
/// Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> If the size of the combined user and system environment variable exceeds 8192 bytes,
/// the process created by <c>CreateProcessAsUser</c> no longer runs with the environment block passed to the function by the parent
/// process. Instead, the child process runs with the environment block returned by the CreateEnvironmentBlock function.
/// </para>
/// <para>To retrieve a copy of the environment block for a given user, use the CreateEnvironmentBlock function.</para>
/// </param>
/// <param name="lpCurrentDirectory">
/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
/// <para>
/// If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature
/// is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
/// </para>
/// </param>
/// <param name="lpStartupInfo">
/// <para>A pointer to a STARTUPINFO or STARTUPINFOEX structure.</para>
/// <para>
/// The user must have full access to both the specified window station and desktop. If you want the process to be interactive,
/// specify winsta0\default. If the <c>lpDesktop</c> member is NULL, the new process inherits the desktop and window station of its
/// parent process. If this member is an empty string, "", the new process connects to a window station using the rules described in
/// Process Connection to a Window Station.
/// </para>
/// <para>
/// To set extended attributes, use a STARTUPINFOEX structure and specify <c>EXTENDED_STARTUPINFO_PRESENT</c> in the dwCreationFlags parameter.
/// </para>
/// <para>Handles in STARTUPINFO or STARTUPINFOEX must be closed with CloseHandle when they are no longer needed.</para>
/// <para>
/// <c>Important</c> The caller is responsible for ensuring that the standard handle fields in STARTUPINFO contain valid handle
/// values. These fields are copied unchanged to the child process without validation, even when the <c>dwFlags</c> member specifies
/// <c>STARTF_USESTDHANDLES</c>. Incorrect values can cause the child process to misbehave or crash. Use the Application Verifier
/// runtime verification tool to detect invalid handles.
/// </para>
/// </param>
/// <param name="lpProcessInformation">
/// <para>A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.</para>
/// <para>Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
/// initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// <c>CreateProcessAsUser</c> must be able to open the primary token of the calling process with the <c>TOKEN_DUPLICATE</c> and
/// <c>TOKEN_IMPERSONATE</c> access rights.
/// </para>
/// <para>
/// By default, <c>CreateProcessAsUser</c> creates the new process on a noninteractive window station with a desktop that is not
/// visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default
/// interactive window station and desktop, "winsta0\default", in the <c>lpDesktop</c> member of the STARTUPINFO structure. In
/// addition, before calling <c>CreateProcessAsUser</c>, you must change the discretionary access control list (DACL) of both the
/// default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the
/// user or the logon session represented by the hToken parameter.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> does not load the specified user's profile into the <c>HKEY_USERS</c> registry key. Therefore, to
/// access the information in the <c>HKEY_CURRENT_USER</c> registry key, you must load the user's profile information into
/// <c>HKEY_USERS</c> with the LoadUserProfile function before calling <c>CreateProcessAsUser</c>. Be sure to call UnloadUserProfile
/// after the new process exits.
/// </para>
/// <para>
/// If the lpEnvironment parameter is NULL, the new process inherits the environment of the calling process.
/// <c>CreateProcessAsUser</c> does not automatically modify the environment block to include environment variables specific to the
/// user represented by hToken. For example, the USERNAME and USERDOMAIN variables are inherited from the calling process if
/// lpEnvironment is NULL. It is your responsibility to prepare the environment block for the new process and specify it in lpEnvironment.
/// </para>
/// <para>
/// The CreateProcessWithLogonW and CreateProcessWithTokenW functions are similar to <c>CreateProcessAsUser</c>, except that the
/// caller does not need to call the LogonUser function to authenticate the user and get a token.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> allows you to access the specified directory and executable image in the security context of the
/// caller or the target user. By default, <c>CreateProcessAsUser</c> accesses the directory and executable image in the security
/// context of the caller. In this case, if the caller does not have access to the directory and executable image, the function
/// fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to
/// the ImpersonateLoggedOnUser function before calling <c>CreateProcessAsUser</c>.
/// </para>
/// <para>
/// The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify
/// the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also
/// assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is
/// valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are
/// returned in the PROCESS_INFORMATION structure.
/// </para>
/// <para>
/// The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is
/// waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because
/// <c>CreateProcessAsUser</c> returns without waiting for the new process to finish its initialization. For example, the creating
/// process would use <c>WaitForInputIdle</c> before trying to find a window associated with the new process.
/// </para>
/// <para>
/// The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of
/// approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached
/// DLLs. Note that when a thread calls <c>ExitProcess</c>, other threads of the process are terminated without an opportunity to
/// execute any additional code (including the thread termination code of attached DLLs). For more information, see Terminating a Process.
/// </para>
/// <para>Security Remarks</para>
/// <para>
/// The lpApplicationName parameter can be NULL, in which case the executable name must be the first white spacedelimited string in
/// lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because
/// of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe",
/// if it exists, instead of "MyApp.exe".
/// </para>
/// <para>
/// If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls
/// <c>CreateProcessAsUser</c> using the Program Files directory will run this application instead of the intended application.
/// </para>
/// <para>
/// To avoid this problem, do not pass NULL for lpApplicationName. If you do pass <c>NULL</c> for lpApplicationName, use quotation
/// marks around the executable path in lpCommandLine, as shown in the example below.
/// </para>
/// <para>
/// <c>PowerShell:</c> When the <c>CreateProcessAsUser</c> function is used to implement a cmdlet in PowerShell version 2.0, the
/// cmdlet operates correctly for both fan-in and fan-out remote sessions. Because of certain security scenarios, however, a cmdlet
/// implemented with <c>CreateProcessAsUser</c> only operates correctly in PowerShell version 3.0 for fan-in remote sessions; fan-out
/// remote sessions will fail because of insufficient client security privileges. To implement a cmdlet that works for both fan-in
/// and fan-out remote sessions in PowerShell version 3.0, use the CreateProcess function.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Starting an Interactive Client Process.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera BOOL
// CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
// LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR
// lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
[PInvokeData("processthreadsapi.h", MSDNShortId = "6b3f4dd9-500b-420e-804a-401a9e188be8")]
public static bool CreateProcessAsUser(HTOKEN hToken, [Optional] string lpApplicationName, [Optional] StringBuilder lpCommandLine, [Optional] SECURITY_ATTRIBUTES lpProcessAttributes,
[Optional] SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, CREATE_PROCESS dwCreationFlags, [In, Optional] string[] lpEnvironment, [Optional] string lpCurrentDirectory,
in STARTUPINFO lpStartupInfo, out SafePROCESS_INFORMATION lpProcessInformation)
{
var ret = CreateProcessAsUser(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
lpCurrentDirectory, lpStartupInfo, out PROCESS_INFORMATION pi);
lpProcessInformation = ret ? new SafePROCESS_INFORMATION(pi) : null;
return ret;
}
/// <summary>
/// <para>
/// Creates a new process and its primary thread. The new process runs in the security context of the user represented by the
/// specified token.
/// </para>
/// <para>
/// Typically, the process that calls the <c>CreateProcessAsUser</c> function must have the <c>SE_INCREASE_QUOTA_NAME</c> privilege
/// and may require the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege if the token is not assignable. If this function fails with
/// <c>ERROR_PRIVILEGE_NOT_HELD</c> (1314), use the CreateProcessWithLogonW function instead. <c>CreateProcessWithLogonW</c> requires
/// no special privileges, but the specified user account must be allowed to log on interactively. Generally, it is best to use
/// <c>CreateProcessWithLogonW</c> to create a process with alternate credentials.
/// </para>
/// </summary>
/// <param name="hToken">
/// <para>
/// A handle to the primary token that represents a user. The handle must have the <c>TOKEN_QUERY</c>, <c>TOKEN_DUPLICATE</c>, and
/// <c>TOKEN_ASSIGN_PRIMARY</c> access rights. For more information, see Access Rights for Access-Token Objects. The user represented
/// by the token must have read and execute access to the application specified by the lpApplicationName or the lpCommandLine parameter.
/// </para>
/// <para>
/// To get a primary token that represents the specified user, call the LogonUser function. Alternatively, you can call the
/// DuplicateTokenEx function to convert an impersonation token into a primary token. This allows a server application that is
/// impersonating a client to create a process that has the security context of the client.
/// </para>
/// <para>
/// If hToken is a restricted version of the caller's primary token, the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege is not required.
/// If the necessary privileges are not already enabled, <c>CreateProcessAsUser</c> enables them for the duration of the call. For
/// more information, see Running with Special Privileges.
/// </para>
/// <para>
/// <c>Terminal Services:</c> The process is run in the session specified in the token. By default, this is the same session that
/// called LogonUser. To change the session, use the SetTokenInformation function.
/// </para>
/// </param>
/// <param name="lpApplicationName">
/// <para>
/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
/// </para>
/// <para>
/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use
/// the search path. This parameter must include the file name extension; no default extension is assumed.
/// </para>
/// <para>
/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white spacedelimited token
/// in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the
/// file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program
/// files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities
/// in the following order:
/// </para>
/// <para>
/// <c>c:\program.exe</c><c>c:\program files\sub.exe</c><c>c:\program files\sub dir\program.exe</c><c>c:\program files\sub
/// dir\program name.exe</c> If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the
/// string pointed to by lpCommandLine should specify the executable module as well as its arguments. By default, all 16-bit
/// Windows-based applications created by <c>CreateProcessAsUser</c> are run in a separate VDM (equivalent to
/// <c>CREATE_SEPARATE_WOW_VDM</c> in CreateProcess).
/// </para>
/// </param>
/// <param name="lpCommandLine">
/// <para>
/// The command line to be executed. The maximum length of this string is 32K characters. If lpApplicationName is <c>NULL</c>, the
/// module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
/// </para>
/// <para>
/// The Unicode version of this function, <c>CreateProcessAsUserW</c>, can modify the contents of this string. Therefore, this
/// parameter cannot be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a
/// constant string, the function may cause an access violation.
/// </para>
/// <para>
/// The lpCommandLine parameter can be <c>NULL</c>. In that case, the function uses the string pointed to by lpApplicationName as the
/// command line.
/// </para>
/// <para>
/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, *lpApplicationName specifies the module to execute, and
/// *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console
/// processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C
/// programmers generally repeat the module name as the first token in the command line.
/// </para>
/// <para>
/// If lpApplicationName is <c>NULL</c>, the first white spacedelimited token of the command line specifies the module name. If you
/// are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin
/// (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended.
/// Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period
/// (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory
/// path, the system searches for the executable file in the following sequence:
/// </para>
/// <list type="number">
/// <item>
/// <term>The directory from which the application loaded.</term>
/// </item>
/// <item>
/// <term>The current directory for the parent process.</term>
/// </item>
/// <item>
/// <term>The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.</term>
/// </item>
/// <item>
/// <term>The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>
/// The directories that are listed in the PATH environment variable. Note that this function does not search the per-application
/// path specified by the <c>App Paths</c> registry key. To include this per-application path in the search sequence, use the
/// ShellExecute function.
/// </term>
/// </item>
/// </list>
/// <para>
/// The system adds a null character to the command line string to separate the file name from the arguments. This divides the
/// original string into two strings for internal processing.
/// </para>
/// </param>
/// <param name="lpProcessAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new process object and determines
/// whether child processes can inherit the returned handle to the process. If lpProcessAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor and the handle cannot be inherited.
/// The default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow
/// access for the caller, in which case the process may not be opened again after it is run. The process handle is valid and will
/// continue to have full access rights.
/// </param>
/// <param name="lpThreadAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread object and determines
/// whether child processes can inherit the returned handle to the thread. If lpThreadAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the thread gets a default security descriptor and the handle cannot be inherited. The
/// default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow access
/// for the caller.
/// </param>
/// <param name="bInheritHandles">
/// <para>
/// If this parameter is <c>TRUE</c>, each inheritable handle in the calling process is inherited by the new process. If the
/// parameter is <c>FALSE</c>, the handles are not inherited. Note that inherited handles have the same value and access rights as
/// the original handles.
/// </para>
/// <para>
/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is <c>TRUE</c>, you must
/// create the process in the same session as the caller.
/// </para>
/// <para>
/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
/// </para>
/// </param>
/// <param name="dwCreationFlags">
/// <para>
/// The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.
/// </para>
/// <para>
/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the
/// process's threads. For a list of values, see GetPriorityClass. If none of the priority class flags is specified, the priority
/// class defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
/// </para>
/// </param>
/// <param name="lpEnvironment">
/// <para>
/// A pointer to an environment block for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of
/// the calling process.
/// </para>
/// <para>An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:</para>
/// <para>name=value\0</para>
/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
/// <para>
/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and
/// the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
/// </para>
/// <para>
/// The ANSI version of this function, <c>CreateProcessAsUserA</c> fails if the total size of the environment block for the process
/// exceeds 32,767 characters.
/// </para>
/// <para>
/// Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A
/// Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> If the size of the combined user and system environment variable exceeds 8192 bytes,
/// the process created by <c>CreateProcessAsUser</c> no longer runs with the environment block passed to the function by the parent
/// process. Instead, the child process runs with the environment block returned by the CreateEnvironmentBlock function.
/// </para>
/// <para>To retrieve a copy of the environment block for a given user, use the CreateEnvironmentBlock function.</para>
/// </param>
/// <param name="lpCurrentDirectory">
/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
/// <para>
/// If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature
/// is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
/// </para>
/// </param>
/// <param name="lpStartupInfo">
/// <para>A pointer to a STARTUPINFO or STARTUPINFOEX structure.</para>
/// <para>
/// The user must have full access to both the specified window station and desktop. If you want the process to be interactive,
/// specify winsta0\default. If the <c>lpDesktop</c> member is NULL, the new process inherits the desktop and window station of its
/// parent process. If this member is an empty string, "", the new process connects to a window station using the rules described in
/// Process Connection to a Window Station.
/// </para>
/// <para>
/// To set extended attributes, use a STARTUPINFOEX structure and specify <c>EXTENDED_STARTUPINFO_PRESENT</c> in the dwCreationFlags parameter.
/// </para>
/// <para>Handles in STARTUPINFO or STARTUPINFOEX must be closed with CloseHandle when they are no longer needed.</para>
/// <para>
/// <c>Important</c> The caller is responsible for ensuring that the standard handle fields in STARTUPINFO contain valid handle
/// values. These fields are copied unchanged to the child process without validation, even when the <c>dwFlags</c> member specifies
/// <c>STARTF_USESTDHANDLES</c>. Incorrect values can cause the child process to misbehave or crash. Use the Application Verifier
/// runtime verification tool to detect invalid handles.
/// </para>
/// </param>
/// <param name="lpProcessInformation">
/// <para>A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.</para>
/// <para>Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
/// initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// <c>CreateProcessAsUser</c> must be able to open the primary token of the calling process with the <c>TOKEN_DUPLICATE</c> and
/// <c>TOKEN_IMPERSONATE</c> access rights.
/// </para>
/// <para>
/// By default, <c>CreateProcessAsUser</c> creates the new process on a noninteractive window station with a desktop that is not
/// visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default
/// interactive window station and desktop, "winsta0\default", in the <c>lpDesktop</c> member of the STARTUPINFO structure. In
/// addition, before calling <c>CreateProcessAsUser</c>, you must change the discretionary access control list (DACL) of both the
/// default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the
/// user or the logon session represented by the hToken parameter.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> does not load the specified user's profile into the <c>HKEY_USERS</c> registry key. Therefore, to
/// access the information in the <c>HKEY_CURRENT_USER</c> registry key, you must load the user's profile information into
/// <c>HKEY_USERS</c> with the LoadUserProfile function before calling <c>CreateProcessAsUser</c>. Be sure to call UnloadUserProfile
/// after the new process exits.
/// </para>
/// <para>
/// If the lpEnvironment parameter is NULL, the new process inherits the environment of the calling process.
/// <c>CreateProcessAsUser</c> does not automatically modify the environment block to include environment variables specific to the
/// user represented by hToken. For example, the USERNAME and USERDOMAIN variables are inherited from the calling process if
/// lpEnvironment is NULL. It is your responsibility to prepare the environment block for the new process and specify it in lpEnvironment.
/// </para>
/// <para>
/// The CreateProcessWithLogonW and CreateProcessWithTokenW functions are similar to <c>CreateProcessAsUser</c>, except that the
/// caller does not need to call the LogonUser function to authenticate the user and get a token.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> allows you to access the specified directory and executable image in the security context of the
/// caller or the target user. By default, <c>CreateProcessAsUser</c> accesses the directory and executable image in the security
/// context of the caller. In this case, if the caller does not have access to the directory and executable image, the function
/// fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to
/// the ImpersonateLoggedOnUser function before calling <c>CreateProcessAsUser</c>.
/// </para>
/// <para>
/// The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify
/// the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also
/// assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is
/// valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are
/// returned in the PROCESS_INFORMATION structure.
/// </para>
/// <para>
/// The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is
/// waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because
/// <c>CreateProcessAsUser</c> returns without waiting for the new process to finish its initialization. For example, the creating
/// process would use <c>WaitForInputIdle</c> before trying to find a window associated with the new process.
/// </para>
/// <para>
/// The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of
/// approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached
/// DLLs. Note that when a thread calls <c>ExitProcess</c>, other threads of the process are terminated without an opportunity to
/// execute any additional code (including the thread termination code of attached DLLs). For more information, see Terminating a Process.
/// </para>
/// <para>Security Remarks</para>
/// <para>
/// The lpApplicationName parameter can be NULL, in which case the executable name must be the first white spacedelimited string in
/// lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because
/// of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe",
/// if it exists, instead of "MyApp.exe".
/// </para>
/// <para>
/// If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls
/// <c>CreateProcessAsUser</c> using the Program Files directory will run this application instead of the intended application.
/// </para>
/// <para>
/// To avoid this problem, do not pass NULL for lpApplicationName. If you do pass <c>NULL</c> for lpApplicationName, use quotation
/// marks around the executable path in lpCommandLine, as shown in the example below.
/// </para>
/// <para>
/// <c>PowerShell:</c> When the <c>CreateProcessAsUser</c> function is used to implement a cmdlet in PowerShell version 2.0, the
/// cmdlet operates correctly for both fan-in and fan-out remote sessions. Because of certain security scenarios, however, a cmdlet
/// implemented with <c>CreateProcessAsUser</c> only operates correctly in PowerShell version 3.0 for fan-in remote sessions; fan-out
/// remote sessions will fail because of insufficient client security privileges. To implement a cmdlet that works for both fan-in
/// and fan-out remote sessions in PowerShell version 3.0, use the CreateProcess function.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Starting an Interactive Client Process.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera BOOL
// CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
// LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR
// lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
[PInvokeData("processthreadsapi.h", MSDNShortId = "6b3f4dd9-500b-420e-804a-401a9e188be8")]
public static bool CreateProcessAsUser(HTOKEN hToken, [Optional] string lpApplicationName, [Optional] StringBuilder lpCommandLine, [Optional] SECURITY_ATTRIBUTES lpProcessAttributes,
[Optional] SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, CREATE_PROCESS dwCreationFlags, [In, Optional] string[] lpEnvironment, [Optional] string lpCurrentDirectory,
in STARTUPINFOEX lpStartupInfo, out SafePROCESS_INFORMATION lpProcessInformation)
{
var ret = CreateProcessAsUser(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
lpCurrentDirectory, lpStartupInfo, out PROCESS_INFORMATION pi);
lpProcessInformation = ret ? new SafePROCESS_INFORMATION(pi) : null;
return ret;
}
/// <summary>The OpenProcessToken function opens the access token associated with a process.</summary>
/// <param name="ProcessHandle">
/// A handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission.
/// </param>
/// <param name="DesiredAccess">
/// Specifies an access mask that specifies the requested types of access to the access token. These requested access types are
/// compared with the discretionary access control list (DACL) of the token to determine which accesses are granted or denied.
/// </param>
/// <param name="TokenHandle">A pointer to a handle that identifies the newly opened access token when the function returns.</param>
/// <returns>
/// If the function succeeds, the function returns nonzero. If the function fails, it returns zero. To get extended error
/// information, call GetLastError.
/// </returns>
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
[PInvokeData("processthreadsapi.h", MSDNShortId = "aa379295")]
public static extern bool OpenProcessToken([In] HPROCESS ProcessHandle, TokenAccess DesiredAccess, out SafeHTOKEN TokenHandle);
/// <summary>The <c>OpenThreadToken</c> function opens the access token associated with a thread.</summary>
/// <param name="ThreadHandle">A handle to the thread whose access token is opened.</param>
/// <param name="DesiredAccess">
/// <para>
/// Specifies an access mask that specifies the requested types of access to the access token. These requested access types are
/// reconciled against the token's discretionary access control list (DACL) to determine which accesses are granted or denied.
/// </para>
/// <para>For a list of access rights for access tokens, see Access Rights for Access-Token Objects.</para>
/// </param>
/// <param name="OpenAsSelf">
/// <para>TRUE if the access check is to be made against the process-level security context.</para>
/// <para>
/// <c>FALSE</c> if the access check is to be made against the current security context of the thread calling the
/// <c>OpenThreadToken</c> function.
/// </para>
/// <para>
/// The OpenAsSelf parameter allows the caller of this function to open the access token of a specified thread when the caller is
/// impersonating a token at <c>SecurityIdentification</c> level. Without this parameter, the calling thread cannot open the access
/// token on the specified thread because it is impossible to open executive-level objects by using the <c>SecurityIdentification</c>
/// impersonation level.
/// </para>
/// </param>
/// <param name="TokenHandle">A pointer to a variable that receives the handle to the newly opened access token.</param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>
/// If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>. If the token has
/// the anonymous impersonation level, the token will not be opened and <c>OpenThreadToken</c> sets ERROR_CANT_OPEN_ANONYMOUS as the error.
/// </para>
/// </returns>
// BOOL WINAPI OpenThreadToken( _In_ HANDLE ThreadHandle, _In_ DWORD DesiredAccess, _In_ BOOL OpenAsSelf, _Out_ PHANDLE TokenHandle); https://msdn.microsoft.com/en-us/library/windows/desktop/aa379296(v=vs.85).aspx
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("processthreadsapi.h", MSDNShortId = "aa379296")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OpenThreadToken([In] HTHREAD ThreadHandle, TokenAccess DesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool OpenAsSelf, out SafeHTOKEN TokenHandle);
/// <summary>
/// The <c>SetThreadToken</c> function assigns an impersonation token to a thread. The function can also cause a thread to stop using
/// an impersonation token.
/// </summary>
/// <param name="Thread">
/// <para>A pointer to a handle to the thread to which the function assigns the impersonation token.</para>
/// <para>If Thread is <c>NULL</c>, the function assigns the impersonation token to the calling thread.</para>
/// </param>
/// <param name="Token">
/// <para>
/// A handle to the impersonation token to assign to the thread. This handle must have been opened with TOKEN_IMPERSONATE access
/// rights. For more information, see Access Rights for Access-Token Objects.
/// </para>
/// <para>If Token is <c>NULL</c>, the function causes the thread to stop using an impersonation token.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
/// </returns>
// BOOL WINAPI SetThreadToken( _In_opt_ PHANDLE Thread, _In_opt_ HANDLE Token); https://msdn.microsoft.com/en-us/library/windows/desktop/aa379590(v=vs.85).aspx
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("processthreadsapi.h", MSDNShortId = "aa379590")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetThreadToken(in HTHREAD Thread, [Optional] HTOKEN Token);
/// <summary>
/// The <c>SetThreadToken</c> function assigns an impersonation token to a thread. The function can also cause a thread to stop using
/// an impersonation token.
/// </summary>
/// <param name="Thread">
/// <para>A pointer to a handle to the thread to which the function assigns the impersonation token.</para>
/// <para>If Thread is <c>NULL</c>, the function assigns the impersonation token to the calling thread.</para>
/// </param>
/// <param name="Token">
/// <para>
/// A handle to the impersonation token to assign to the thread. This handle must have been opened with TOKEN_IMPERSONATE access
/// rights. For more information, see Access Rights for Access-Token Objects.
/// </para>
/// <para>If Token is <c>NULL</c>, the function causes the thread to stop using an impersonation token.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call <c>GetLastError</c>.</para>
/// </returns>
// BOOL WINAPI SetThreadToken( _In_opt_ PHANDLE Thread, _In_opt_ HANDLE Token); https://msdn.microsoft.com/en-us/library/windows/desktop/aa379590(v=vs.85).aspx
[DllImport(Lib.AdvApi32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("processthreadsapi.h", MSDNShortId = "aa379590")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetThreadToken([Optional] IntPtr Thread, [Optional] HTOKEN Token);
/// <summary>
/// <para>
/// Creates a new process and its primary thread. The new process runs in the security context of the user represented by the
/// specified token.
/// </para>
/// <para>
/// Typically, the process that calls the <c>CreateProcessAsUser</c> function must have the <c>SE_INCREASE_QUOTA_NAME</c> privilege
/// and may require the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege if the token is not assignable. If this function fails with
/// <c>ERROR_PRIVILEGE_NOT_HELD</c> (1314), use the CreateProcessWithLogonW function instead. <c>CreateProcessWithLogonW</c> requires
/// no special privileges, but the specified user account must be allowed to log on interactively. Generally, it is best to use
/// <c>CreateProcessWithLogonW</c> to create a process with alternate credentials.
/// </para>
/// </summary>
/// <param name="hToken">
/// <para>
/// A handle to the primary token that represents a user. The handle must have the <c>TOKEN_QUERY</c>, <c>TOKEN_DUPLICATE</c>, and
/// <c>TOKEN_ASSIGN_PRIMARY</c> access rights. For more information, see Access Rights for Access-Token Objects. The user represented
/// by the token must have read and execute access to the application specified by the lpApplicationName or the lpCommandLine parameter.
/// </para>
/// <para>
/// To get a primary token that represents the specified user, call the LogonUser function. Alternatively, you can call the
/// DuplicateTokenEx function to convert an impersonation token into a primary token. This allows a server application that is
/// impersonating a client to create a process that has the security context of the client.
/// </para>
/// <para>
/// If hToken is a restricted version of the caller's primary token, the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege is not required.
/// If the necessary privileges are not already enabled, <c>CreateProcessAsUser</c> enables them for the duration of the call. For
/// more information, see Running with Special Privileges.
/// </para>
/// <para>
/// <c>Terminal Services:</c> The process is run in the session specified in the token. By default, this is the same session that
/// called LogonUser. To change the session, use the SetTokenInformation function.
/// </para>
/// </param>
/// <param name="lpApplicationName">
/// <para>
/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
/// </para>
/// <para>
/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use
/// the search path. This parameter must include the file name extension; no default extension is assumed.
/// </para>
/// <para>
/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white spacedelimited token
/// in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the
/// file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program
/// files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities
/// in the following order:
/// </para>
/// <para>
/// <c>c:\program.exe</c><c>c:\program files\sub.exe</c><c>c:\program files\sub dir\program.exe</c><c>c:\program files\sub
/// dir\program name.exe</c> If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the
/// string pointed to by lpCommandLine should specify the executable module as well as its arguments. By default, all 16-bit
/// Windows-based applications created by <c>CreateProcessAsUser</c> are run in a separate VDM (equivalent to
/// <c>CREATE_SEPARATE_WOW_VDM</c> in CreateProcess).
/// </para>
/// </param>
/// <param name="lpCommandLine">
/// <para>
/// The command line to be executed. The maximum length of this string is 32K characters. If lpApplicationName is <c>NULL</c>, the
/// module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
/// </para>
/// <para>
/// The Unicode version of this function, <c>CreateProcessAsUserW</c>, can modify the contents of this string. Therefore, this
/// parameter cannot be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a
/// constant string, the function may cause an access violation.
/// </para>
/// <para>
/// The lpCommandLine parameter can be <c>NULL</c>. In that case, the function uses the string pointed to by lpApplicationName as the
/// command line.
/// </para>
/// <para>
/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, *lpApplicationName specifies the module to execute, and
/// *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console
/// processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C
/// programmers generally repeat the module name as the first token in the command line.
/// </para>
/// <para>
/// If lpApplicationName is <c>NULL</c>, the first white spacedelimited token of the command line specifies the module name. If you
/// are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin
/// (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended.
/// Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period
/// (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory
/// path, the system searches for the executable file in the following sequence:
/// </para>
/// <list type="number">
/// <item>
/// <term>The directory from which the application loaded.</term>
/// </item>
/// <item>
/// <term>The current directory for the parent process.</term>
/// </item>
/// <item>
/// <term>The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.</term>
/// </item>
/// <item>
/// <term>The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>
/// The directories that are listed in the PATH environment variable. Note that this function does not search the per-application
/// path specified by the <c>App Paths</c> registry key. To include this per-application path in the search sequence, use the
/// ShellExecute function.
/// </term>
/// </item>
/// </list>
/// <para>
/// The system adds a null character to the command line string to separate the file name from the arguments. This divides the
/// original string into two strings for internal processing.
/// </para>
/// </param>
/// <param name="lpProcessAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new process object and determines
/// whether child processes can inherit the returned handle to the process. If lpProcessAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor and the handle cannot be inherited.
/// The default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow
/// access for the caller, in which case the process may not be opened again after it is run. The process handle is valid and will
/// continue to have full access rights.
/// </param>
/// <param name="lpThreadAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread object and determines
/// whether child processes can inherit the returned handle to the thread. If lpThreadAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the thread gets a default security descriptor and the handle cannot be inherited. The
/// default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow access
/// for the caller.
/// </param>
/// <param name="bInheritHandles">
/// <para>
/// If this parameter is <c>TRUE</c>, each inheritable handle in the calling process is inherited by the new process. If the
/// parameter is <c>FALSE</c>, the handles are not inherited. Note that inherited handles have the same value and access rights as
/// the original handles.
/// </para>
/// <para>
/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is <c>TRUE</c>, you must
/// create the process in the same session as the caller.
/// </para>
/// <para>
/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
/// </para>
/// </param>
/// <param name="dwCreationFlags">
/// <para>
/// The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.
/// </para>
/// <para>
/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the
/// process's threads. For a list of values, see GetPriorityClass. If none of the priority class flags is specified, the priority
/// class defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
/// </para>
/// </param>
/// <param name="lpEnvironment">
/// <para>
/// A pointer to an environment block for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of
/// the calling process.
/// </para>
/// <para>An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:</para>
/// <para>name=value\0</para>
/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
/// <para>
/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and
/// the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
/// </para>
/// <para>
/// The ANSI version of this function, <c>CreateProcessAsUserA</c> fails if the total size of the environment block for the process
/// exceeds 32,767 characters.
/// </para>
/// <para>
/// Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A
/// Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> If the size of the combined user and system environment variable exceeds 8192 bytes,
/// the process created by <c>CreateProcessAsUser</c> no longer runs with the environment block passed to the function by the parent
/// process. Instead, the child process runs with the environment block returned by the CreateEnvironmentBlock function.
/// </para>
/// <para>To retrieve a copy of the environment block for a given user, use the CreateEnvironmentBlock function.</para>
/// </param>
/// <param name="lpCurrentDirectory">
/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
/// <para>
/// If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature
/// is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
/// </para>
/// </param>
/// <param name="lpStartupInfo">
/// <para>A pointer to a STARTUPINFO or STARTUPINFOEX structure.</para>
/// <para>
/// The user must have full access to both the specified window station and desktop. If you want the process to be interactive,
/// specify winsta0\default. If the <c>lpDesktop</c> member is NULL, the new process inherits the desktop and window station of its
/// parent process. If this member is an empty string, "", the new process connects to a window station using the rules described in
/// Process Connection to a Window Station.
/// </para>
/// <para>
/// To set extended attributes, use a STARTUPINFOEX structure and specify <c>EXTENDED_STARTUPINFO_PRESENT</c> in the dwCreationFlags parameter.
/// </para>
/// <para>Handles in STARTUPINFO or STARTUPINFOEX must be closed with CloseHandle when they are no longer needed.</para>
/// <para>
/// <c>Important</c> The caller is responsible for ensuring that the standard handle fields in STARTUPINFO contain valid handle
/// values. These fields are copied unchanged to the child process without validation, even when the <c>dwFlags</c> member specifies
/// <c>STARTF_USESTDHANDLES</c>. Incorrect values can cause the child process to misbehave or crash. Use the Application Verifier
/// runtime verification tool to detect invalid handles.
/// </para>
/// </param>
/// <param name="lpProcessInformation">
/// <para>A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.</para>
/// <para>Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
/// initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// <c>CreateProcessAsUser</c> must be able to open the primary token of the calling process with the <c>TOKEN_DUPLICATE</c> and
/// <c>TOKEN_IMPERSONATE</c> access rights.
/// </para>
/// <para>
/// By default, <c>CreateProcessAsUser</c> creates the new process on a noninteractive window station with a desktop that is not
/// visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default
/// interactive window station and desktop, "winsta0\default", in the <c>lpDesktop</c> member of the STARTUPINFO structure. In
/// addition, before calling <c>CreateProcessAsUser</c>, you must change the discretionary access control list (DACL) of both the
/// default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the
/// user or the logon session represented by the hToken parameter.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> does not load the specified user's profile into the <c>HKEY_USERS</c> registry key. Therefore, to
/// access the information in the <c>HKEY_CURRENT_USER</c> registry key, you must load the user's profile information into
/// <c>HKEY_USERS</c> with the LoadUserProfile function before calling <c>CreateProcessAsUser</c>. Be sure to call UnloadUserProfile
/// after the new process exits.
/// </para>
/// <para>
/// If the lpEnvironment parameter is NULL, the new process inherits the environment of the calling process.
/// <c>CreateProcessAsUser</c> does not automatically modify the environment block to include environment variables specific to the
/// user represented by hToken. For example, the USERNAME and USERDOMAIN variables are inherited from the calling process if
/// lpEnvironment is NULL. It is your responsibility to prepare the environment block for the new process and specify it in lpEnvironment.
/// </para>
/// <para>
/// The CreateProcessWithLogonW and CreateProcessWithTokenW functions are similar to <c>CreateProcessAsUser</c>, except that the
/// caller does not need to call the LogonUser function to authenticate the user and get a token.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> allows you to access the specified directory and executable image in the security context of the
/// caller or the target user. By default, <c>CreateProcessAsUser</c> accesses the directory and executable image in the security
/// context of the caller. In this case, if the caller does not have access to the directory and executable image, the function
/// fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to
/// the ImpersonateLoggedOnUser function before calling <c>CreateProcessAsUser</c>.
/// </para>
/// <para>
/// The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify
/// the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also
/// assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is
/// valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are
/// returned in the PROCESS_INFORMATION structure.
/// </para>
/// <para>
/// The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is
/// waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because
/// <c>CreateProcessAsUser</c> returns without waiting for the new process to finish its initialization. For example, the creating
/// process would use <c>WaitForInputIdle</c> before trying to find a window associated with the new process.
/// </para>
/// <para>
/// The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of
/// approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached
/// DLLs. Note that when a thread calls <c>ExitProcess</c>, other threads of the process are terminated without an opportunity to
/// execute any additional code (including the thread termination code of attached DLLs). For more information, see Terminating a Process.
/// </para>
/// <para>Security Remarks</para>
/// <para>
/// The lpApplicationName parameter can be NULL, in which case the executable name must be the first white spacedelimited string in
/// lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because
/// of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe",
/// if it exists, instead of "MyApp.exe".
/// </para>
/// <para>
/// If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls
/// <c>CreateProcessAsUser</c> using the Program Files directory will run this application instead of the intended application.
/// </para>
/// <para>
/// To avoid this problem, do not pass NULL for lpApplicationName. If you do pass <c>NULL</c> for lpApplicationName, use quotation
/// marks around the executable path in lpCommandLine, as shown in the example below.
/// </para>
/// <para>
/// <c>PowerShell:</c> When the <c>CreateProcessAsUser</c> function is used to implement a cmdlet in PowerShell version 2.0, the
/// cmdlet operates correctly for both fan-in and fan-out remote sessions. Because of certain security scenarios, however, a cmdlet
/// implemented with <c>CreateProcessAsUser</c> only operates correctly in PowerShell version 3.0 for fan-in remote sessions; fan-out
/// remote sessions will fail because of insufficient client security privileges. To implement a cmdlet that works for both fan-in
/// and fan-out remote sessions in PowerShell version 3.0, use the CreateProcess function.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Starting an Interactive Client Process.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera BOOL
// CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
// LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR
// lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("processthreadsapi.h", MSDNShortId = "6b3f4dd9-500b-420e-804a-401a9e188be8")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateProcessAsUser(HTOKEN hToken, [Optional] string lpApplicationName, [Optional] StringBuilder lpCommandLine,
[Optional] SECURITY_ATTRIBUTES lpProcessAttributes, [Optional] SECURITY_ATTRIBUTES lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
CREATE_PROCESS dwCreationFlags, [In, Optional, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[] lpEnvironment,
[Optional] string lpCurrentDirectory, in STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
/// <summary>
/// <para>
/// Creates a new process and its primary thread. The new process runs in the security context of the user represented by the
/// specified token.
/// </para>
/// <para>
/// Typically, the process that calls the <c>CreateProcessAsUser</c> function must have the <c>SE_INCREASE_QUOTA_NAME</c> privilege
/// and may require the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege if the token is not assignable. If this function fails with
/// <c>ERROR_PRIVILEGE_NOT_HELD</c> (1314), use the CreateProcessWithLogonW function instead. <c>CreateProcessWithLogonW</c> requires
/// no special privileges, but the specified user account must be allowed to log on interactively. Generally, it is best to use
/// <c>CreateProcessWithLogonW</c> to create a process with alternate credentials.
/// </para>
/// </summary>
/// <param name="hToken">
/// <para>
/// A handle to the primary token that represents a user. The handle must have the <c>TOKEN_QUERY</c>, <c>TOKEN_DUPLICATE</c>, and
/// <c>TOKEN_ASSIGN_PRIMARY</c> access rights. For more information, see Access Rights for Access-Token Objects. The user represented
/// by the token must have read and execute access to the application specified by the lpApplicationName or the lpCommandLine parameter.
/// </para>
/// <para>
/// To get a primary token that represents the specified user, call the LogonUser function. Alternatively, you can call the
/// DuplicateTokenEx function to convert an impersonation token into a primary token. This allows a server application that is
/// impersonating a client to create a process that has the security context of the client.
/// </para>
/// <para>
/// If hToken is a restricted version of the caller's primary token, the <c>SE_ASSIGNPRIMARYTOKEN_NAME</c> privilege is not required.
/// If the necessary privileges are not already enabled, <c>CreateProcessAsUser</c> enables them for the duration of the call. For
/// more information, see Running with Special Privileges.
/// </para>
/// <para>
/// <c>Terminal Services:</c> The process is run in the session specified in the token. By default, this is the same session that
/// called LogonUser. To change the session, use the SetTokenInformation function.
/// </para>
/// </param>
/// <param name="lpApplicationName">
/// <para>
/// The name of the module to be executed. This module can be a Windows-based application. It can be some other type of module (for
/// example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.
/// </para>
/// <para>
/// The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a
/// partial name, the function uses the current drive and current directory to complete the specification. The function will not use
/// the search path. This parameter must include the file name extension; no default extension is assumed.
/// </para>
/// <para>
/// The lpApplicationName parameter can be <c>NULL</c>. In that case, the module name must be the first white spacedelimited token
/// in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the
/// file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program
/// files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities
/// in the following order:
/// </para>
/// <para>
/// <c>c:\program.exe</c><c>c:\program files\sub.exe</c><c>c:\program files\sub dir\program.exe</c><c>c:\program files\sub
/// dir\program name.exe</c> If the executable module is a 16-bit application, lpApplicationName should be <c>NULL</c>, and the
/// string pointed to by lpCommandLine should specify the executable module as well as its arguments. By default, all 16-bit
/// Windows-based applications created by <c>CreateProcessAsUser</c> are run in a separate VDM (equivalent to
/// <c>CREATE_SEPARATE_WOW_VDM</c> in CreateProcess).
/// </para>
/// </param>
/// <param name="lpCommandLine">
/// <para>
/// The command line to be executed. The maximum length of this string is 32K characters. If lpApplicationName is <c>NULL</c>, the
/// module name portion of lpCommandLine is limited to <c>MAX_PATH</c> characters.
/// </para>
/// <para>
/// The Unicode version of this function, <c>CreateProcessAsUserW</c>, can modify the contents of this string. Therefore, this
/// parameter cannot be a pointer to read-only memory (such as a <c>const</c> variable or a literal string). If this parameter is a
/// constant string, the function may cause an access violation.
/// </para>
/// <para>
/// The lpCommandLine parameter can be <c>NULL</c>. In that case, the function uses the string pointed to by lpApplicationName as the
/// command line.
/// </para>
/// <para>
/// If both lpApplicationName and lpCommandLine are non- <c>NULL</c>, *lpApplicationName specifies the module to execute, and
/// *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console
/// processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C
/// programmers generally repeat the module name as the first token in the command line.
/// </para>
/// <para>
/// If lpApplicationName is <c>NULL</c>, the first white spacedelimited token of the command line specifies the module name. If you
/// are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin
/// (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended.
/// Therefore, if the file name extension is .com, this parameter must include the .com extension. If the file name ends in a period
/// (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory
/// path, the system searches for the executable file in the following sequence:
/// </para>
/// <list type="number">
/// <item>
/// <term>The directory from which the application loaded.</term>
/// </item>
/// <item>
/// <term>The current directory for the parent process.</term>
/// </item>
/// <item>
/// <term>The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.</term>
/// </item>
/// <item>
/// <term>The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.</term>
/// </item>
/// <item>
/// <term>
/// The directories that are listed in the PATH environment variable. Note that this function does not search the per-application
/// path specified by the <c>App Paths</c> registry key. To include this per-application path in the search sequence, use the
/// ShellExecute function.
/// </term>
/// </item>
/// </list>
/// <para>
/// The system adds a null character to the command line string to separate the file name from the arguments. This divides the
/// original string into two strings for internal processing.
/// </para>
/// </param>
/// <param name="lpProcessAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new process object and determines
/// whether child processes can inherit the returned handle to the process. If lpProcessAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the process gets a default security descriptor and the handle cannot be inherited.
/// The default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow
/// access for the caller, in which case the process may not be opened again after it is run. The process handle is valid and will
/// continue to have full access rights.
/// </param>
/// <param name="lpThreadAttributes">
/// A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread object and determines
/// whether child processes can inherit the returned handle to the thread. If lpThreadAttributes is <c>NULL</c> or
/// <c>lpSecurityDescriptor</c> is <c>NULL</c>, the thread gets a default security descriptor and the handle cannot be inherited. The
/// default security descriptor is that of the user referenced in the hToken parameter. This security descriptor may not allow access
/// for the caller.
/// </param>
/// <param name="bInheritHandles">
/// <para>
/// If this parameter is <c>TRUE</c>, each inheritable handle in the calling process is inherited by the new process. If the
/// parameter is <c>FALSE</c>, the handles are not inherited. Note that inherited handles have the same value and access rights as
/// the original handles.
/// </para>
/// <para>
/// <c>Terminal Services:</c> You cannot inherit handles across sessions. Additionally, if this parameter is <c>TRUE</c>, you must
/// create the process in the same session as the caller.
/// </para>
/// <para>
/// <c>Protected Process Light (PPL) processes:</c> The generic handle inheritance is blocked when a PPL process creates a non-PPL
/// process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights
/// </para>
/// </param>
/// <param name="dwCreationFlags">
/// <para>
/// The flags that control the priority class and the creation of the process. For a list of values, see Process Creation Flags.
/// </para>
/// <para>
/// This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the
/// process's threads. For a list of values, see GetPriorityClass. If none of the priority class flags is specified, the priority
/// class defaults to <c>NORMAL_PRIORITY_CLASS</c> unless the priority class of the creating process is <c>IDLE_PRIORITY_CLASS</c> or
/// <c>BELOW_NORMAL_PRIORITY_CLASS</c>. In this case, the child process receives the default priority class of the calling process.
/// </para>
/// </param>
/// <param name="lpEnvironment">
/// <para>
/// A pointer to an environment block for the new process. If this parameter is <c>NULL</c>, the new process uses the environment of
/// the calling process.
/// </para>
/// <para>An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:</para>
/// <para>name=value\0</para>
/// <para>Because the equal sign is used as a separator, it must not be used in the name of an environment variable.</para>
/// <para>
/// An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains
/// Unicode characters, be sure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>. If this parameter is <c>NULL</c> and
/// the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes <c>CREATE_UNICODE_ENVIRONMENT</c>.
/// </para>
/// <para>
/// The ANSI version of this function, <c>CreateProcessAsUserA</c> fails if the total size of the environment block for the process
/// exceeds 32,767 characters.
/// </para>
/// <para>
/// Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A
/// Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.
/// </para>
/// <para>
/// <c>Windows Server 2003 and Windows XP:</c> If the size of the combined user and system environment variable exceeds 8192 bytes,
/// the process created by <c>CreateProcessAsUser</c> no longer runs with the environment block passed to the function by the parent
/// process. Instead, the child process runs with the environment block returned by the CreateEnvironmentBlock function.
/// </para>
/// <para>To retrieve a copy of the environment block for a given user, use the CreateEnvironmentBlock function.</para>
/// </param>
/// <param name="lpCurrentDirectory">
/// <para>The full path to the current directory for the process. The string can also specify a UNC path.</para>
/// <para>
/// If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature
/// is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
/// </para>
/// </param>
/// <param name="lpStartupInfo">
/// <para>A pointer to a STARTUPINFO or STARTUPINFOEX structure.</para>
/// <para>
/// The user must have full access to both the specified window station and desktop. If you want the process to be interactive,
/// specify winsta0\default. If the <c>lpDesktop</c> member is NULL, the new process inherits the desktop and window station of its
/// parent process. If this member is an empty string, "", the new process connects to a window station using the rules described in
/// Process Connection to a Window Station.
/// </para>
/// <para>
/// To set extended attributes, use a STARTUPINFOEX structure and specify <c>EXTENDED_STARTUPINFO_PRESENT</c> in the dwCreationFlags parameter.
/// </para>
/// <para>Handles in STARTUPINFO or STARTUPINFOEX must be closed with CloseHandle when they are no longer needed.</para>
/// <para>
/// <c>Important</c> The caller is responsible for ensuring that the standard handle fields in STARTUPINFO contain valid handle
/// values. These fields are copied unchanged to the child process without validation, even when the <c>dwFlags</c> member specifies
/// <c>STARTF_USESTDHANDLES</c>. Incorrect values can cause the child process to misbehave or crash. Use the Application Verifier
/// runtime verification tool to detect invalid handles.
/// </para>
/// </param>
/// <param name="lpProcessInformation">
/// <para>A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.</para>
/// <para>Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.</para>
/// </param>
/// <returns>
/// <para>If the function succeeds, the return value is nonzero.</para>
/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
/// <para>
/// Note that the function returns before the process has finished initialization. If a required DLL cannot be located or fails to
/// initialize, the process is terminated. To get the termination status of a process, call GetExitCodeProcess.
/// </para>
/// </returns>
/// <remarks>
/// <para>
/// <c>CreateProcessAsUser</c> must be able to open the primary token of the calling process with the <c>TOKEN_DUPLICATE</c> and
/// <c>TOKEN_IMPERSONATE</c> access rights.
/// </para>
/// <para>
/// By default, <c>CreateProcessAsUser</c> creates the new process on a noninteractive window station with a desktop that is not
/// visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default
/// interactive window station and desktop, "winsta0\default", in the <c>lpDesktop</c> member of the STARTUPINFO structure. In
/// addition, before calling <c>CreateProcessAsUser</c>, you must change the discretionary access control list (DACL) of both the
/// default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the
/// user or the logon session represented by the hToken parameter.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> does not load the specified user's profile into the <c>HKEY_USERS</c> registry key. Therefore, to
/// access the information in the <c>HKEY_CURRENT_USER</c> registry key, you must load the user's profile information into
/// <c>HKEY_USERS</c> with the LoadUserProfile function before calling <c>CreateProcessAsUser</c>. Be sure to call UnloadUserProfile
/// after the new process exits.
/// </para>
/// <para>
/// If the lpEnvironment parameter is NULL, the new process inherits the environment of the calling process.
/// <c>CreateProcessAsUser</c> does not automatically modify the environment block to include environment variables specific to the
/// user represented by hToken. For example, the USERNAME and USERDOMAIN variables are inherited from the calling process if
/// lpEnvironment is NULL. It is your responsibility to prepare the environment block for the new process and specify it in lpEnvironment.
/// </para>
/// <para>
/// The CreateProcessWithLogonW and CreateProcessWithTokenW functions are similar to <c>CreateProcessAsUser</c>, except that the
/// caller does not need to call the LogonUser function to authenticate the user and get a token.
/// </para>
/// <para>
/// <c>CreateProcessAsUser</c> allows you to access the specified directory and executable image in the security context of the
/// caller or the target user. By default, <c>CreateProcessAsUser</c> accesses the directory and executable image in the security
/// context of the caller. In this case, if the caller does not have access to the directory and executable image, the function
/// fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to
/// the ImpersonateLoggedOnUser function before calling <c>CreateProcessAsUser</c>.
/// </para>
/// <para>
/// The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify
/// the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also
/// assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is
/// valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are
/// returned in the PROCESS_INFORMATION structure.
/// </para>
/// <para>
/// The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is
/// waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because
/// <c>CreateProcessAsUser</c> returns without waiting for the new process to finish its initialization. For example, the creating
/// process would use <c>WaitForInputIdle</c> before trying to find a window associated with the new process.
/// </para>
/// <para>
/// The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of
/// approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached
/// DLLs. Note that when a thread calls <c>ExitProcess</c>, other threads of the process are terminated without an opportunity to
/// execute any additional code (including the thread termination code of attached DLLs). For more information, see Terminating a Process.
/// </para>
/// <para>Security Remarks</para>
/// <para>
/// The lpApplicationName parameter can be NULL, in which case the executable name must be the first white spacedelimited string in
/// lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because
/// of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe",
/// if it exists, instead of "MyApp.exe".
/// </para>
/// <para>
/// If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls
/// <c>CreateProcessAsUser</c> using the Program Files directory will run this application instead of the intended application.
/// </para>
/// <para>
/// To avoid this problem, do not pass NULL for lpApplicationName. If you do pass <c>NULL</c> for lpApplicationName, use quotation
/// marks around the executable path in lpCommandLine, as shown in the example below.
/// </para>
/// <para>
/// <c>PowerShell:</c> When the <c>CreateProcessAsUser</c> function is used to implement a cmdlet in PowerShell version 2.0, the
/// cmdlet operates correctly for both fan-in and fan-out remote sessions. Because of certain security scenarios, however, a cmdlet
/// implemented with <c>CreateProcessAsUser</c> only operates correctly in PowerShell version 3.0 for fan-in remote sessions; fan-out
/// remote sessions will fail because of insufficient client security privileges. To implement a cmdlet that works for both fan-in
/// and fan-out remote sessions in PowerShell version 3.0, use the CreateProcess function.
/// </para>
/// <para>Examples</para>
/// <para>For an example, see Starting an Interactive Client Process.</para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera BOOL
// CreateProcessAsUserA( HANDLE hToken, LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
// LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR
// lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation );
[DllImport(Lib.AdvApi32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("processthreadsapi.h", MSDNShortId = "6b3f4dd9-500b-420e-804a-401a9e188be8")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateProcessAsUser(HTOKEN hToken, [Optional] string lpApplicationName, [Optional] StringBuilder lpCommandLine,
[Optional] SECURITY_ATTRIBUTES lpProcessAttributes, [Optional] SECURITY_ATTRIBUTES lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles,
CREATE_PROCESS dwCreationFlags, [In, Optional, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(NullTermStringArrayMarshaler), MarshalCookie = "Auto")] string[] lpEnvironment,
[Optional] string lpCurrentDirectory, in STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
}
}