/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo) { // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points: // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so // that the child process can not close them // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use // GetStdHandle for the handles that are not being redirected StringBuilder commandLine = BuildCommandLine(startInfo.FileName, StartInfo.Arguments); Process.AppendArguments(commandLine, StartInfo.ArgumentList); Interop.Kernel32.STARTUPINFO startupInfo = new Interop.Kernel32.STARTUPINFO(); Interop.Kernel32.PROCESS_INFORMATION processInfo = new Interop.Kernel32.PROCESS_INFORMATION(); Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); // handles used in parent process SafeFileHandle parentInputPipeHandle = null; SafeFileHandle childInputPipeHandle = null; SafeFileHandle parentOutputPipeHandle = null; SafeFileHandle childOutputPipeHandle = null; SafeFileHandle parentErrorPipeHandle = null; SafeFileHandle childErrorPipeHandle = null; lock (s_createProcessLock) { try { startupInfo.cb = sizeof(Interop.Kernel32.STARTUPINFO); // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out parentInputPipeHandle, out childInputPipeHandle, true); } else { childInputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out parentOutputPipeHandle, out childOutputPipeHandle, false); } else { childOutputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out parentErrorPipeHandle, out childErrorPipeHandle, false); } else { childErrorPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.hStdInput = childInputPipeHandle.DangerousGetHandle(); startupInfo.hStdOutput = childOutputPipeHandle.DangerousGetHandle(); startupInfo.hStdError = childErrorPipeHandle.DangerousGetHandle(); startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags parameter int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW; } // set up the environment block parameter string environmentBlock = null; if (startInfo._environmentVariables != null) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) { workingDirectory = Directory.GetCurrentDirectory(); } bool retVal; int errorCode = 0; if (startInfo.UserName.Length != 0) { if (startInfo.Password != null && startInfo.PasswordInClearText != null) { throw new ArgumentException(SR.CantSetDuplicatePassword); } Interop.Advapi32.LogonFlags logonFlags = (Interop.Advapi32.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.Advapi32.LogonFlags.LOGON_WITH_PROFILE; } fixed(char *passwordInClearTextPtr = startInfo.PasswordInClearText ?? string.Empty) fixed(char *environmentBlockPtr = environmentBlock) { IntPtr passwordPtr = (startInfo.Password != null) ? Marshal.SecureStringToGlobalAllocUnicode(startInfo.Password) : IntPtr.Zero; try { retVal = Interop.Advapi32.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, (passwordPtr != IntPtr.Zero) ? passwordPtr : (IntPtr)passwordInClearTextPtr, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, (IntPtr)environmentBlockPtr, workingDirectory, ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } finally { if (passwordPtr != IntPtr.Zero) { Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr); } } } } else { fixed(char *environmentBlockPtr = environmentBlock) { retVal = Interop.Kernel32.CreateProcess( null, // we don't need this since all the info is in commandLine commandLine, // pointer to the command line string ref unused_SecAttrs, // address to process security attributes, we don't need to inherit the handle ref unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags (IntPtr)environmentBlockPtr, // pointer to new environment block workingDirectory, // pointer to current directory name ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != new IntPtr(-1)) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != new IntPtr(-1)) { threadSH.InitialSetHandle(processInfo.hThread); } if (!retVal) { if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } finally { childInputPipeHandle?.Dispose(); childOutputPipeHandle?.Dispose(); childErrorPipeHandle?.Dispose(); threadSH?.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = startInfo.StandardInputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(parentErrorPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (procSH.IsInvalid) { return(false); } SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); return(true); }
private unsafe bool StartWithShellExecuteEx(ProcessStartInfo startInfo) { if (!string.IsNullOrEmpty(startInfo.UserName) || startInfo.Password != null) { throw new InvalidOperationException(SR.CantStartAsUser); } if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { throw new InvalidOperationException(SR.CantRedirectStreams); } if (startInfo.StandardInputEncoding != null) { throw new InvalidOperationException(SR.StandardInputEncodingNotAllowed); } if (startInfo.StandardErrorEncoding != null) { throw new InvalidOperationException(SR.StandardErrorEncodingNotAllowed); } if (startInfo.StandardOutputEncoding != null) { throw new InvalidOperationException(SR.StandardOutputEncodingNotAllowed); } if (startInfo._environmentVariables != null) { throw new InvalidOperationException(SR.CantUseEnvVars); } string arguments; if (startInfo.ArgumentList.Count > 0) { StringBuilder sb = new StringBuilder(); Process.AppendArguments(sb, startInfo.ArgumentList); arguments = sb.ToString(); } else { arguments = startInfo.Arguments; } fixed(char *fileName = startInfo.FileName.Length > 0?startInfo.FileName : null) fixed(char *verb = startInfo.Verb.Length > 0 ? startInfo.Verb : null) fixed(char *parameters = arguments.Length > 0 ? arguments : null) fixed(char *directory = startInfo.WorkingDirectory.Length > 0 ? startInfo.WorkingDirectory : null) { Interop.Shell32.SHELLEXECUTEINFO shellExecuteInfo = new Interop.Shell32.SHELLEXECUTEINFO() { cbSize = (uint)sizeof(Interop.Shell32.SHELLEXECUTEINFO), lpFile = fileName, lpVerb = verb, lpParameters = parameters, lpDirectory = directory, fMask = Interop.Shell32.SEE_MASK_NOCLOSEPROCESS | Interop.Shell32.SEE_MASK_FLAG_DDEWAIT }; if (startInfo.ErrorDialog) { shellExecuteInfo.hwnd = startInfo.ErrorDialogParentHandle; } else { shellExecuteInfo.fMask |= Interop.Shell32.SEE_MASK_FLAG_NO_UI; } switch (startInfo.WindowStyle) { case ProcessWindowStyle.Hidden: shellExecuteInfo.nShow = Interop.Shell32.SW_HIDE; break; case ProcessWindowStyle.Minimized: shellExecuteInfo.nShow = Interop.Shell32.SW_SHOWMINIMIZED; break; case ProcessWindowStyle.Maximized: shellExecuteInfo.nShow = Interop.Shell32.SW_SHOWMAXIMIZED; break; default: shellExecuteInfo.nShow = Interop.Shell32.SW_SHOWNORMAL; break; } ShellExecuteHelper executeHelper = new ShellExecuteHelper(&shellExecuteInfo); if (!executeHelper.ShellExecuteOnSTAThread()) { int error = executeHelper.ErrorCode; if (error == 0) { error = GetShellError(shellExecuteInfo.hInstApp); } switch (error) { case Interop.Errors.ERROR_BAD_EXE_FORMAT: case Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH: throw new Win32Exception(error, SR.InvalidApplication); case Interop.Errors.ERROR_CALL_NOT_IMPLEMENTED: // This happens on Windows Nano throw new PlatformNotSupportedException(SR.UseShellExecuteNotSupported); default: throw new Win32Exception(error); } } if (shellExecuteInfo.hProcess != IntPtr.Zero) { SetProcessHandle(new SafeProcessHandle(shellExecuteInfo.hProcess)); return(true); } } return(false); }