예제 #1
0
        private static unsafe void StartProcess(string[] args, NativeJob job)
        {
            using (var atts = new ProcThreadAttributeList(1))
                using (var shellProc = GetShellProcess()) {
                    IntPtr shellHandle = shellProc.Handle.DangerousGetHandle();

                    atts.AddAttribute <IntPtr>(ProcThreadAttribute.ParentProcess, &shellHandle);

                    using (NativeProcess natProcess = NativeProcess.CreateProcess(args[0], null, CreateProcessFlags.None, StartupInfoFlags.None, atts, null, out _)) {
                        job.AttachProcess(natProcess);
                    }
                }
        }
예제 #2
0
        private static unsafe (int processId, SafeProcessHandle processHandle, SafeThreadHandle threadHandle) InvokeCreateProcess(
            StringBuilder commandLine,
            int creationFlags,
            char[]?environmentBlock,
            string?workingDirectory,
            SafeHandle?childStdIn,
            SafeHandle?childStdOut,
            SafeHandle?childStdErr,
            ProcThreadAttributeList attr)
        {
            var nativeSi = new Kernel32.STARTUPINFOEX()
            {
                cb              = sizeof(Kernel32.STARTUPINFOEX),
                dwFlags         = Kernel32.STARTF_USESTDHANDLES,
                hStdInput       = childStdIn?.DangerousGetHandle() ?? IntPtr.Zero,
                hStdOutput      = childStdOut?.DangerousGetHandle() ?? IntPtr.Zero,
                hStdError       = childStdErr?.DangerousGetHandle() ?? IntPtr.Zero,
                lpAttributeList = attr.DangerousGetHandle(),
            };

            fixed(char *pEnvironmentBlock = environmentBlock)
            {
                if (!Kernel32.CreateProcess(
                        null,
                        commandLine,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        true,
                        creationFlags,
                        pEnvironmentBlock,
                        workingDirectory,
                        ref nativeSi,
                        out var pi))
                {
                    throw new Win32Exception();
                }

                return(pi.dwProcessId, new SafeProcessHandle(pi.hProcess, true), new SafeThreadHandle(pi.hThread, true));
            }
        }
        public unsafe IChildProcessStateHolder SpawnProcess(
            ref ChildProcessStartInfoInternal startInfo,
            string resolvedPath,
            SafeHandle stdIn,
            SafeHandle stdOut,
            SafeHandle stdErr)
        {
            var arguments            = startInfo.Arguments;
            var environmentVariables = startInfo.EnvironmentVariables;
            var workingDirectory     = startInfo.WorkingDirectory;
            var flags = startInfo.Flags;

            Debug.Assert(startInfo.CreateNewConsole || ConsolePal.HasConsoleWindow());

            var commandLine      = WindowsCommandLineUtil.MakeCommandLine(resolvedPath, arguments ?? Array.Empty <string>(), !flags.HasDisableArgumentQuoting());
            var environmentBlock = environmentVariables != null?WindowsEnvironmentBlockUtil.MakeEnvironmentBlock(environmentVariables) : null;

            var pseudoConsole = startInfo.CreateNewConsole ? InputWriterOnlyPseudoConsole.Create() : null;

            try
            {
                if (pseudoConsole is { } && flags.HasUseCustomCodePage())
                {
                    ChangeCodePage(pseudoConsole, startInfo.CodePage, workingDirectory);
                }

                using var inheritableHandleStore = new InheritableHandleStore(3);
                var childStdIn = stdIn != null?inheritableHandleStore.Add(stdIn) : null;

                var childStdOut = stdOut != null?inheritableHandleStore.Add(stdOut) : null;

                var childStdErr = stdErr != null?inheritableHandleStore.Add(stdErr) : null;

                Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count];
                inheritableHandleStore.DangerousGetHandles(inheritableHandles);
                fixed(IntPtr *pInheritableHandles = inheritableHandles)
                {
                    using var attr = new ProcThreadAttributeList(2);
                    if (pseudoConsole is { })
예제 #4
0
 internal StartupInfoExW(StartupInfoW StartupInfo, ProcThreadAttributeList atts)
 {
     this.StartupInfo    = StartupInfo;
     this.StartupInfo.cb = (uint)sizeof(StartupInfoExW);
     attributeList       = atts.lpAttributeList;
 }
예제 #5
0
        public unsafe IChildProcessStateHolder SpawnProcess(
            ref ChildProcessStartInfoInternal startInfo,
            string resolvedPath,
            SafeHandle stdIn,
            SafeHandle stdOut,
            SafeHandle stdErr)
        {
            var arguments            = startInfo.Arguments;
            var environmentVariables = startInfo.EnvironmentVariables;
            var workingDirectory     = startInfo.WorkingDirectory;
            var flags = startInfo.Flags;

            Debug.Assert(startInfo.CreateNewConsole || ConsolePal.HasConsoleWindow());

            var commandLine      = WindowsCommandLineUtil.MakeCommandLine(resolvedPath, arguments ?? Array.Empty <string>(), !flags.HasDisableArgumentQuoting());
            var environmentBlock = startInfo.UseCustomEnvironmentVariables ? WindowsEnvironmentBlockUtil.MakeEnvironmentBlock(environmentVariables.Span) : null;

            // Objects that need cleanup
            InputWriterOnlyPseudoConsole?pseudoConsole   = null;
            SafeJobObjectHandle?         jobObjectHandle = null;
            SafeProcessHandle?           processHandle   = null;
            SafeThreadHandle?            threadHandle    = null;

            try
            {
                pseudoConsole = startInfo.CreateNewConsole ? InputWriterOnlyPseudoConsole.Create() : null;
                if (pseudoConsole is not null && flags.HasUseCustomCodePage())
                {
                    ChangeCodePage(pseudoConsole, startInfo.CodePage, workingDirectory);
                }

                bool killOnClose = startInfo.AllowSignal && WindowsVersion.NeedsWorkaroundForWindows1809;
                jobObjectHandle = CreateJobObject(killOnClose, startInfo.DisableWindowsErrorReportingDialog);

                using var inheritableHandleStore = new InheritableHandleStore(3);
                var childStdIn = stdIn != null?inheritableHandleStore.Add(stdIn) : null;

                var childStdOut = stdOut != null?inheritableHandleStore.Add(stdOut) : null;

                var childStdErr = stdErr != null?inheritableHandleStore.Add(stdErr) : null;

                IntPtr jobObjectHandles = jobObjectHandle.DangerousGetHandle();

                Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count];
                inheritableHandleStore.DangerousGetHandles(inheritableHandles);
                fixed(IntPtr *pInheritableHandles = inheritableHandles)
                {
                    using var attr = new ProcThreadAttributeList(3);
                    if (pseudoConsole is not null)
                    {
                        attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle());
                    }
                    attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length);
                    attr.UpdateJobList(&jobObjectHandles, 1);

                    const int CreationFlags =
                        Kernel32.CREATE_UNICODE_ENVIRONMENT
                        | Kernel32.EXTENDED_STARTUPINFO_PRESENT;

                    int processId;

                    (processId, processHandle, threadHandle) = InvokeCreateProcess(
                        commandLine,
                        CreationFlags,
                        environmentBlock,
                        workingDirectory,
                        childStdIn,
                        childStdOut,
                        childStdErr,
                        attr);

                    return(new WindowsChildProcessState(processId, processHandle, jobObjectHandle, pseudoConsole, startInfo.AllowSignal));
                }
            }
            catch
            {
                if (processHandle is not null)
                {
                    Kernel32.TerminateProcess(processHandle, -1);
                    processHandle.Dispose();
                }
                pseudoConsole?.Dispose();
                jobObjectHandle?.Dispose();
                throw;
            }
            finally
            {
                threadHandle?.Dispose();
            }
        }
예제 #6
0
        // Change the code page of the specified pseudo console by invoking chcp.com on it.
        private static unsafe void ChangeCodePage(
            InputWriterOnlyPseudoConsole pseudoConsole,
            int codePage,
            string?workingDirectory)
        {
            var commandLine = new StringBuilder(ChcpPath.Length + 5);

            WindowsCommandLineUtil.AppendStringQuoted(commandLine, ChcpPath);
            commandLine.Append(' ');
            commandLine.Append(codePage.ToString(CultureInfo.InvariantCulture));

            using var inheritableHandleStore = new InheritableHandleStore(3);
            using var nullDevice             = FilePal.OpenNullDevice(FileAccess.ReadWrite);
            var childStdIn  = inheritableHandleStore.Add(nullDevice);
            var childStdOut = inheritableHandleStore.Add(nullDevice);
            var childStdErr = inheritableHandleStore.Add(nullDevice);

            SafeProcessHandle?processHandle = null;

            try
            {
                Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count];
                inheritableHandleStore.DangerousGetHandles(inheritableHandles);
                fixed(IntPtr *pInheritableHandles = inheritableHandles)
                {
                    using var attr = new ProcThreadAttributeList(2);
                    attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle());
                    attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length);

                    const int CreationFlags =
                        Kernel32.CREATE_UNICODE_ENVIRONMENT
                        | Kernel32.EXTENDED_STARTUPINFO_PRESENT;

                    SafeThreadHandle threadHandle;

                    (_, processHandle, threadHandle) = InvokeCreateProcess(
                        commandLine,
                        CreationFlags,
                        null,
                        workingDirectory,
                        childStdIn,
                        childStdOut,
                        childStdErr,
                        attr);
                    threadHandle.Dispose();
                }

                using var waitHandle = new WindowsProcessWaitHandle(processHandle);
                waitHandle.WaitOne();

                if (!Kernel32.GetExitCodeProcess(processHandle, out var exitCode))
                {
                    throw new Win32Exception();
                }

                if (exitCode != 0)
                {
                    ThrowHelper.ThrowChcpFailedException(codePage, exitCode, nameof(codePage));
                }
            }
            finally
            {
                processHandle?.Dispose();
            }
        }