/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private bool StartCore(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); Interop.mincore.STARTUPINFO startupInfo = new Interop.mincore.STARTUPINFO(); Interop.mincore.PROCESS_INFORMATION processInfo = new Interop.mincore.PROCESS_INFORMATION(); Interop.mincore.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.mincore.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); bool retVal; int errorCode = 0; // handles used in parent process SafeFileHandle standardInputWritePipeHandle = null; SafeFileHandle standardOutputReadPipeHandle = null; SafeFileHandle standardErrorReadPipeHandle = null; GCHandle environmentHandle = new GCHandle(); lock (s_createProcessLock) { try { // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true); } else { startupInfo.hStdInput = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false); } else { startupInfo.hStdOutput = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false); } else { startupInfo.hStdError = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.dwFlags = Interop.mincore.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags parameter int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.mincore.StartupInfoOptions.CREATE_NO_WINDOW; } // set up the environment block parameter IntPtr environmentPtr = (IntPtr)0; if (startInfo._environmentVariables != null) { creationFlags |= Interop.mincore.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; byte[] environmentBytes = EnvironmentVariablesToByteArray(startInfo._environmentVariables); environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned); environmentPtr = environmentHandle.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) { workingDirectory = Directory.GetCurrentDirectory(); } if (startInfo.UserName.Length != 0) { Interop.mincore.LogonFlags logonFlags = (Interop.mincore.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.mincore.LogonFlags.LOGON_WITH_PROFILE; } try { } finally { retVal = Interop.mincore.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, startInfo.PasswordInClearText, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, environmentPtr, workingDirectory, startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(processInfo.hThread); } } if (!retVal) { if (errorCode == Interop.mincore.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.mincore.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } else { try { } finally { retVal = Interop.mincore.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 environmentPtr, // pointer to new environment block workingDirectory, // pointer to current directory name startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE) { procSH.InitialSetHandle(processInfo.hProcess); } if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE) { threadSH.InitialSetHandle(processInfo.hThread); } } if (!retVal) { if (errorCode == Interop.mincore.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.mincore.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) { throw new Win32Exception(errorCode, SR.InvalidApplication); } throw new Win32Exception(errorCode); } } } finally { // free environment block if (environmentHandle.IsAllocated) { environmentHandle.Free(); } startupInfo.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = GetEncoding((int)Interop.mincore.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.mincore.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.mincore.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } bool ret = false; if (!procSH.IsInvalid) { SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); threadSH.Dispose(); ret = true; } return(ret); }
/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private bool StartCore(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); Interop.mincore.STARTUPINFO startupInfo = new Interop.mincore.STARTUPINFO(); Interop.mincore.PROCESS_INFORMATION processInfo = new Interop.mincore.PROCESS_INFORMATION(); Interop.mincore.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.mincore.SECURITY_ATTRIBUTES(); SafeProcessHandle procSH = new SafeProcessHandle(); SafeThreadHandle threadSH = new SafeThreadHandle(); bool retVal; int errorCode = 0; // handles used in parent process SafeFileHandle standardInputWritePipeHandle = null; SafeFileHandle standardOutputReadPipeHandle = null; SafeFileHandle standardErrorReadPipeHandle = null; GCHandle environmentHandle = new GCHandle(); lock (s_createProcessLock) { try { // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true); } else { startupInfo.hStdInput = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false); } else { startupInfo.hStdOutput = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false); } else { startupInfo.hStdError = new SafeFileHandle(Interop.mincore.GetStdHandle(Interop.mincore.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.dwFlags = Interop.mincore.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags paramater int creationFlags = 0; if (startInfo.CreateNoWindow) creationFlags |= Interop.mincore.StartupInfoOptions.CREATE_NO_WINDOW; // set up the environment block parameter IntPtr environmentPtr = (IntPtr)0; if (startInfo._environmentVariables != null) { creationFlags |= Interop.mincore.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; byte[] environmentBytes = EnvironmentVariablesToByteArray(startInfo._environmentVariables); environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned); environmentPtr = environmentHandle.AddrOfPinnedObject(); } string workingDirectory = startInfo.WorkingDirectory; if (workingDirectory == string.Empty) workingDirectory = Directory.GetCurrentDirectory(); if (startInfo.UserName.Length != 0) { Interop.mincore.LogonFlags logonFlags = (Interop.mincore.LogonFlags)0; if (startInfo.LoadUserProfile) { logonFlags = Interop.mincore.LogonFlags.LOGON_WITH_PROFILE; } try { } finally { retVal = Interop.mincore.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, startInfo.PasswordInClearText, logonFlags, null, // we don't need this since all the info is in commandLine commandLine, creationFlags, environmentPtr, workingDirectory, startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) errorCode = Marshal.GetLastWin32Error(); if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE) procSH.InitialSetHandle(processInfo.hProcess); if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE) threadSH.InitialSetHandle(processInfo.hThread); } if (!retVal) { if (errorCode == Interop.mincore.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.mincore.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) throw new Win32Exception(errorCode, SR.InvalidApplication); throw new Win32Exception(errorCode); } } else { try { } finally { retVal = Interop.mincore.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 inheriat the handle ref unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags environmentPtr, // pointer to new environment block workingDirectory, // pointer to current directory name startupInfo, // pointer to STARTUPINFO processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) errorCode = Marshal.GetLastWin32Error(); if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE) procSH.InitialSetHandle(processInfo.hProcess); if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE) threadSH.InitialSetHandle(processInfo.hThread); } if (!retVal) { if (errorCode == Interop.mincore.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.mincore.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH) throw new Win32Exception(errorCode, SR.InvalidApplication); throw new Win32Exception(errorCode); } } } finally { // free environment block if (environmentHandle.IsAllocated) { environmentHandle.Free(); } startupInfo.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = GetEncoding((int)Interop.mincore.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.mincore.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.mincore.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096); } bool ret = false; if (!procSH.IsInvalid) { SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); threadSH.Dispose(); ret = true; } return ret; }