Пример #1
1
        /// <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);
        }
Пример #2
0
        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        //                                  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);
        }