示例#1
0
        /// <summary>
        /// Creates a new MSBuild process
        /// </summary>
        private Process LaunchNode(string msbuildLocation, string commandLineArgs)
        {
            // Should always have been set already.
            ErrorUtilities.VerifyThrowInternalLength(msbuildLocation, nameof(msbuildLocation));

            if (!FileSystems.Default.FileExists(msbuildLocation))
            {
                throw new BuildAbortedException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("CouldNotFindMSBuildExe", msbuildLocation));
            }

            // Repeat the executable name as the first token of the command line because the command line
            // parser logic expects it and will otherwise skip the first argument
            commandLineArgs = $"\"{msbuildLocation}\" {commandLineArgs}";

            BackendNativeMethods.STARTUP_INFO startInfo = new();
            startInfo.cb = Marshal.SizeOf <BackendNativeMethods.STARTUP_INFO>();

            // Null out the process handles so that the parent process does not wait for the child process
            // to exit before it can exit.
            uint creationFlags = 0;

            if (Traits.Instance.EscapeHatches.EnsureStdOutForChildNodesIsPrimaryStdout)
            {
                creationFlags = BackendNativeMethods.NORMALPRIORITYCLASS;
            }

            if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDNODEWINDOW")))
            {
                if (!Traits.Instance.EscapeHatches.EnsureStdOutForChildNodesIsPrimaryStdout)
                {
                    // Redirect the streams of worker nodes so that this MSBuild.exe's
                    // parent doesn't wait on idle worker nodes to close streams
                    // after the build is complete.
                    startInfo.hStdError  = BackendNativeMethods.InvalidHandle;
                    startInfo.hStdInput  = BackendNativeMethods.InvalidHandle;
                    startInfo.hStdOutput = BackendNativeMethods.InvalidHandle;
                    startInfo.dwFlags    = BackendNativeMethods.STARTFUSESTDHANDLES;
                    creationFlags       |= BackendNativeMethods.CREATENOWINDOW;
                }
            }
            else
            {
                creationFlags |= BackendNativeMethods.CREATE_NEW_CONSOLE;
            }

            CommunicationsUtilities.Trace("Launching node from {0}", msbuildLocation);

            string exeName = msbuildLocation;

#if RUNTIME_TYPE_NETCORE || MONO
            // Mono automagically uses the current mono, to execute a managed assembly
            if (!NativeMethodsShared.IsMono)
            {
                // Run the child process with the same host as the currently-running process.
                exeName = GetCurrentHost();
            }
#endif

            if (!NativeMethodsShared.IsWindows)
            {
                ProcessStartInfo processStartInfo = new ProcessStartInfo();
                processStartInfo.FileName  = exeName;
                processStartInfo.Arguments = commandLineArgs;
                if (!Traits.Instance.EscapeHatches.EnsureStdOutForChildNodesIsPrimaryStdout)
                {
                    // Redirect the streams of worker nodes so that this MSBuild.exe's
                    // parent doesn't wait on idle worker nodes to close streams
                    // after the build is complete.
                    processStartInfo.RedirectStandardInput  = true;
                    processStartInfo.RedirectStandardOutput = true;
                    processStartInfo.RedirectStandardError  = true;
                    processStartInfo.CreateNoWindow         = (creationFlags | BackendNativeMethods.CREATENOWINDOW) == BackendNativeMethods.CREATENOWINDOW;
                }
                processStartInfo.UseShellExecute = false;

                Process process;
                try
                {
                    process = Process.Start(processStartInfo);
                }
                catch (Exception ex)
                {
                    CommunicationsUtilities.Trace
                    (
                        "Failed to launch node from {0}. CommandLine: {1}" + Environment.NewLine + "{2}",
                        msbuildLocation,
                        commandLineArgs,
                        ex.ToString()
                    );

                    throw new NodeFailedToLaunchException(ex);
                }

                CommunicationsUtilities.Trace("Successfully launched {1} node with PID {0}", process.Id, exeName);
                return(process);
            }
            else
            {
#if RUNTIME_TYPE_NETCORE
                // Repeat the executable name in the args to suit CreateProcess
                commandLineArgs = $"\"{exeName}\" {commandLineArgs}";
#endif

                BackendNativeMethods.PROCESS_INFORMATION processInfo = new();
                BackendNativeMethods.SECURITY_ATTRIBUTES processSecurityAttributes = new();
                BackendNativeMethods.SECURITY_ATTRIBUTES threadSecurityAttributes  = new();
                processSecurityAttributes.nLength = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>();
                threadSecurityAttributes.nLength  = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>();

                bool result = BackendNativeMethods.CreateProcess
                              (
                    exeName,
                    commandLineArgs,
                    ref processSecurityAttributes,
                    ref threadSecurityAttributes,
                    false,
                    creationFlags,
                    BackendNativeMethods.NullPtr,
                    null,
                    ref startInfo,
                    out processInfo
                              );

                if (!result)
                {
                    // Creating an instance of this exception calls GetLastWin32Error and also converts it to a user-friendly string.
                    System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception();

                    CommunicationsUtilities.Trace
                    (
                        "Failed to launch node from {0}. System32 Error code {1}. Description {2}. CommandLine: {2}",
                        msbuildLocation,
                        e.NativeErrorCode.ToString(CultureInfo.InvariantCulture),
                        e.Message,
                        commandLineArgs
                    );

                    throw new NodeFailedToLaunchException(e.NativeErrorCode.ToString(CultureInfo.InvariantCulture), e.Message);
                }

                int childProcessId = processInfo.dwProcessId;

                if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != NativeMethods.InvalidHandle)
                {
                    NativeMethodsShared.CloseHandle(processInfo.hProcess);
                }

                if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != NativeMethods.InvalidHandle)
                {
                    NativeMethodsShared.CloseHandle(processInfo.hThread);
                }

                CommunicationsUtilities.Trace("Successfully launched {1} node with PID {0}", childProcessId, exeName);
                return(Process.GetProcessById(childProcessId));
            }
        }
示例#2
0
        /// <summary>
        /// Creates a new MSBuild process
        /// </summary>
        private int LaunchNode(string msbuildLocation, string commandLineArgs)
        {
            // Should always have been set already.
            ErrorUtilities.VerifyThrowInternalLength(msbuildLocation, "msbuildLocation");

            if (!File.Exists(msbuildLocation))
            {
                throw new BuildAbortedException(ResourceUtilities.FormatResourceString("CouldNotFindMSBuildExe", msbuildLocation));
            }

            // Repeat the executable name as the first token of the command line because the command line
            // parser logic expects it and will otherwise skip the first argument
            commandLineArgs = msbuildLocation + " " + commandLineArgs;

            BackendNativeMethods.STARTUP_INFO startInfo = new BackendNativeMethods.STARTUP_INFO();
            startInfo.cb = Marshal.SizeOf <BackendNativeMethods.STARTUP_INFO>();

            // Null out the process handles so that the parent process does not wait for the child process
            // to exit before it can exit.
            uint creationFlags = 0;

            startInfo.dwFlags = BackendNativeMethods.STARTFUSESTDHANDLES;

            if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDNODEWINDOW")))
            {
                startInfo.hStdError  = BackendNativeMethods.InvalidHandle;
                startInfo.hStdInput  = BackendNativeMethods.InvalidHandle;
                startInfo.hStdOutput = BackendNativeMethods.InvalidHandle;
                creationFlags        = creationFlags | BackendNativeMethods.CREATENOWINDOW;
            }
            else
            {
                creationFlags = creationFlags | BackendNativeMethods.CREATE_NEW_CONSOLE;
            }

            BackendNativeMethods.SECURITY_ATTRIBUTES processSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES();
            BackendNativeMethods.SECURITY_ATTRIBUTES threadSecurityAttributes  = new BackendNativeMethods.SECURITY_ATTRIBUTES();
            processSecurityAttributes.nLength = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>();
            threadSecurityAttributes.nLength  = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>();

            CommunicationsUtilities.Trace("Launching node from {0}", msbuildLocation);

            string exeName = msbuildLocation;

#if RUNTIME_TYPE_NETCORE
            // Run the child process with the same host as the currently-running process.
            exeName         = GetCurrentHost();
            commandLineArgs = "\"" + msbuildLocation + "\" " + commandLineArgs;

            if (NativeMethodsShared.IsWindows)
            {
                // Repeat the executable name _again_ because Core MSBuild expects it
                commandLineArgs = exeName + " " + commandLineArgs;
            }
#endif

            if (!NativeMethodsShared.IsWindows)
            {
                ProcessStartInfo processStartInfo = new ProcessStartInfo();
                processStartInfo.FileName        = exeName;
                processStartInfo.Arguments       = commandLineArgs;
                processStartInfo.CreateNoWindow  = (creationFlags | BackendNativeMethods.CREATENOWINDOW) == BackendNativeMethods.CREATENOWINDOW;
                processStartInfo.UseShellExecute = false;

                Process process;
                try
                {
                    process = Process.Start(processStartInfo);
                }
                catch (Exception ex)
                {
                    CommunicationsUtilities.Trace
                    (
                        "Failed to launch node from {0}. CommandLine: {1}" + Environment.NewLine + "{2}",
                        msbuildLocation,
                        commandLineArgs,
                        ex.ToString()
                    );

                    throw new NodeFailedToLaunchException(ex);
                }

                CommunicationsUtilities.Trace("Successfully launched msbuild.exe node with PID {0}", process.Id);
                return(process.Id);
            }
            else
            {
                BackendNativeMethods.PROCESS_INFORMATION processInfo = new BackendNativeMethods.PROCESS_INFORMATION();

                bool result = BackendNativeMethods.CreateProcess
                              (
                    exeName,
                    commandLineArgs,
                    ref processSecurityAttributes,
                    ref threadSecurityAttributes,
#if FEATURE_NAMED_PIPES_FULL_DUPLEX
                    false,
#else
                    true,     // Inherit handles for the anonymous pipes for IPC
#endif
                    creationFlags,
                    BackendNativeMethods.NullPtr,
                    null,
                    ref startInfo,
                    out processInfo
                              );

                if (!result)
                {
                    // Creating an instance of this exception calls GetLastWin32Error and also converts it to a user-friendly string.
                    System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception();

                    CommunicationsUtilities.Trace
                    (
                        "Failed to launch node from {0}. System32 Error code {1}. Description {2}. CommandLine: {2}",
                        msbuildLocation,
                        e.NativeErrorCode.ToString(CultureInfo.InvariantCulture),
                        e.Message,
                        commandLineArgs
                    );

                    throw new NodeFailedToLaunchException(e.NativeErrorCode.ToString(CultureInfo.InvariantCulture), e.Message);
                }

                int childProcessId = processInfo.dwProcessId;

                if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != NativeMethods.InvalidHandle)
                {
                    NativeMethodsShared.CloseHandle(processInfo.hProcess);
                }

                if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != NativeMethods.InvalidHandle)
                {
                    NativeMethodsShared.CloseHandle(processInfo.hThread);
                }

                CommunicationsUtilities.Trace("Successfully launched msbuild.exe node with PID {0}", childProcessId);
                return(childProcessId);
            }
        }