/// <summary> /// !!! to be checked /// </summary> /// <param name="appPath"></param> /// <param name="cmdLine"></param> /// <param name="workDir"></param> /// <param name="visible"></param> /// <returns></returns> public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true) { var hUserToken = IntPtr.Zero; Advapi32.STARTUPINFO startInfo = new Advapi32.STARTUPINFO(); WinApi.Advapi32.PROCESS_INFORMATION procInfo = default; var pEnv = IntPtr.Zero; int iResultOfCreateProcessAsUser; startInfo.cb = Marshal.SizeOf(typeof(Advapi32.STARTUPINFO)); try { if (!getActiveSessionUserToken(ref hUserToken)) { throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed."); } Advapi32.CreationFlags dwCreationFlags = Advapi32.CreationFlags.CREATE_UNICODE_ENVIRONMENT | (visible ? Advapi32.CreationFlags.CREATE_NEW_CONSOLE : Advapi32.CreationFlags.CREATE_NO_WINDOW); startInfo.wShowWindow = (short)(visible ? User32.SW.SW_SHOW : User32.SW.SW_HIDE); //startInfo.lpDesktop = "winsta0\\default"; if (!Userenv.CreateEnvironmentBlock(ref pEnv, hUserToken, false)) { throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed."); } if (!Advapi32.CreateProcessAsUser(hUserToken, appPath, // Application Name cmdLine, // Command Line null, null, false, dwCreationFlags, pEnv, workDir, // Working directory startInfo, procInfo)) { iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error(); throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed. Error Code -" + iResultOfCreateProcessAsUser); } iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error(); } finally { Kernel32.CloseHandle(hUserToken); if (pEnv != IntPtr.Zero) { Userenv.DestroyEnvironmentBlock(pEnv); } Kernel32.CloseHandle(procInfo.hThread); Kernel32.CloseHandle(procInfo.hProcess); } return(true); }
////////////////////////////////////////////////////////////////////////////////////////////////////////// // Start, Stop, Pause, Resume, etc // ////////////////////////////////////////////////////////////////////////////////////////////////////////// #region Start/Stop/Pause/Resume/etc /// <summary> /// Start the process. /// </summary> /// <exception cref="Win32Exception"></exception> internal void StartProcess(string username) { //CloseProcess old instances StopProcess(); var startupInfo = new Kernel32.StartupInfo(); var processInformation = new Kernel32.ProcessInformation(); IntPtr environment = IntPtr.Zero; //Flags that specify the priority and creation method of the process Kernel32.CreationFlags creationFlags = Kernel32.CreationFlags.CreateUnicodeEnvironment | //Windows 7+ always using the unicode environment Kernel32.CreationFlags.CreateNewConsole | _serviceDefinition.ProcessPriority.ConvertToCreationFlag(); //Set the startupinfo startupInfo.cb = (uint)Marshal.SizeOf(startupInfo); startupInfo.desktop = "winsta0\\default"; //Create command line arguments var cmdLine = ""; if (string.Equals(Path.GetExtension(_serviceDefinition.BinaryPath), ".bat", StringComparison.OrdinalIgnoreCase)) { cmdLine = "cmd.exe /c"; } cmdLine += BuildDoubleQuotedString(_serviceDefinition.BinaryPath); if (!string.IsNullOrWhiteSpace(_serviceDefinition.Arguments)) { cmdLine += " " + _serviceDefinition.Arguments; } try { if (string.IsNullOrWhiteSpace(username)) { //Set last start in user session _lastStartInUserSession = false; _lastSessionUsername = string.Empty; if (!Kernel32.CreateProcess( null, cmdLine, null, null, false, creationFlags, IntPtr.Zero, //TODO: Change Path.GetDirectoryName(_serviceDefinition.BinaryPath), ref startupInfo, out processInformation)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } else { //Set last start in user session _lastStartInUserSession = true; _lastSessionUsername = username; //Get user token using (SafeAccessTokenHandle token = TokenHelper.GetPrimaryTokenByUsername(username)) { if (token == null) { throw new Exception("GetPrimaryTokenByUsername: No valid session found."); } //Create environment block if (!Userenv.CreateEnvironmentBlock(ref environment, token, false)) { throw new Exception("StartInUserSession: CreateEnvironmentBlock failed."); } WindowsIdentity.RunImpersonated(token, () => { if (!Advapi32.CreateProcessAsUser( token, null, cmdLine, null, null, false, creationFlags, environment, Path.GetDirectoryName(_serviceDefinition.BinaryPath), ref startupInfo, out processInformation)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } }); } } } finally { if (environment != IntPtr.Zero) { Userenv.DestroyEnvironmentBlock(environment); } if (processInformation.processHandle != IntPtr.Zero) { Kernel32.CloseHandle(processInformation.processHandle); } if (processInformation.threadHandle != IntPtr.Zero) { Kernel32.CloseHandle(processInformation.threadHandle); } } //Get process and enable raising events _process = Process.GetProcessById((int)processInformation.processId); _process.EnableRaisingEvents = true; _process.Exited += ProcessOnExited; //Assign process to job if (KillChildProcessJob.IsSupportedWindowsVersion) { _killChildProcessJob.AssignProcess(_process); } _lastRestartTime = DateTime.UtcNow; //Trigger event to update pid OnUpdateProcessPid(processInformation.processId); }