Ejemplo n.º 1
0
        /// <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,
            });
        }