/// <summary> /// Wrapper around the Win32 CreateProcess API for low level use. This just spawns the new process and does not /// wait until it is complete before returning. /// </summary> /// <param name="applicationName">The name of the executable or batch file to execute</param> /// <param name="commandLine">The command line to execute, typically this includes applicationName as the first argument</param> /// <param name="processAttributes">SecurityAttributes to assign to the new process, set to null to use the defaults</param> /// <param name="threadAttributes">SecurityAttributes to assign to the new thread, set to null to use the defaults</param> /// <param name="inheritHandles">Any inheritable handles in the calling process is inherited in the new process</param> /// <param name="creationFlags">Custom creation flags to use when creating the new process</param> /// <param name="environment">A dictionary of key/value pairs to define the new process environment</param> /// <param name="currentDirectory">The full path to the current directory for the process, null will have the same cwd as the calling process</param> /// <param name="startupInfo">Custom StartupInformation to use when creating the new process</param> /// <returns>ProcessInformation containing a handle to the process and main thread as well as the pid/tid.</returns> public static ProcessInformation NativeCreateProcess(string applicationName, string commandLine, SecurityAttributes processAttributes, SecurityAttributes threadAttributes, bool inheritHandles, ProcessCreationFlags creationFlags, IDictionary environment, string currentDirectory, StartupInfo startupInfo) { // We always have the extended version present. creationFlags |= ProcessCreationFlags.ExtendedStartupInfoPresent; // $null from PowerShell ends up as an empty string, we need to convert back as an empty string doesn't // make sense for these parameters if (String.IsNullOrWhiteSpace(applicationName)) { applicationName = null; } if (String.IsNullOrWhiteSpace(currentDirectory)) { currentDirectory = null; } NativeHelpers.STARTUPINFOEX si = new NativeHelpers.STARTUPINFOEX(); if (!String.IsNullOrWhiteSpace(startupInfo.Desktop)) { si.startupInfo.lpDesktop = startupInfo.Desktop; } if (!String.IsNullOrWhiteSpace(startupInfo.Title)) { si.startupInfo.lpTitle = startupInfo.Title; } bool useStdHandles = false; if (startupInfo.StandardInput != null) { si.startupInfo.hStdInput = startupInfo.StandardInput; useStdHandles = true; } if (startupInfo.StandardOutput != null) { si.startupInfo.hStdOutput = startupInfo.StandardOutput; useStdHandles = true; } if (startupInfo.StandardError != null) { si.startupInfo.hStdError = startupInfo.StandardError; useStdHandles = true; } if (useStdHandles) { si.startupInfo.dwFlags |= NativeHelpers.StartupInfoFlags.USESTDHANDLES; } if (startupInfo.WindowStyle != null) { switch (startupInfo.WindowStyle) { case ProcessWindowStyle.Normal: si.startupInfo.wShowWindow = 1; // SW_SHOWNORMAL break; case ProcessWindowStyle.Hidden: si.startupInfo.wShowWindow = 0; // SW_HIDE break; case ProcessWindowStyle.Minimized: si.startupInfo.wShowWindow = 6; // SW_MINIMIZE break; case ProcessWindowStyle.Maximized: si.startupInfo.wShowWindow = 3; // SW_MAXIMIZE break; } si.startupInfo.dwFlags |= NativeHelpers.StartupInfoFlags.STARTF_USESHOWWINDOW; } NativeHelpers.PROCESS_INFORMATION pi = new NativeHelpers.PROCESS_INFORMATION(); using (SafeMemoryBuffer lpProcessAttr = CreateSecurityAttributes(processAttributes)) using (SafeMemoryBuffer lpThreadAttributes = CreateSecurityAttributes(threadAttributes)) using (SafeMemoryBuffer lpEnvironment = CreateEnvironmentPointer(environment)) { StringBuilder commandLineBuff = new StringBuilder(commandLine); if (!NativeMethods.CreateProcessW(applicationName, commandLineBuff, lpProcessAttr, lpThreadAttributes, inheritHandles, creationFlags, lpEnvironment, currentDirectory, si, out pi)) { throw new Win32Exception("CreateProcessW() failed"); } } return(new ProcessInformation { Process = new SafeNativeHandle(pi.hProcess), Thread = new SafeNativeHandle(pi.hThread), ProcessId = pi.dwProcessId, ThreadId = pi.dwThreadId, }); }