File: System\Runtime\InteropServices\WindowsProcessStartArguments.cs
Web Access
Project: src\runtime\src\libraries\System.Diagnostics.Process\src\System.Diagnostics.Process.csproj (System.Diagnostics.Process)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Runtime.Versioning;

namespace System.Runtime.InteropServices
{
    /// <summary>
    /// Provides the prepared data required to start a process via a user-supplied callback.
    /// This ref struct is populated by the <see cref="Start(ProcessStartInfo, Func{WindowsProcessStartArguments, nint})"/> method.
    /// </summary>
    public readonly ref struct WindowsProcessStartArguments
    {
        internal unsafe WindowsProcessStartArguments(char* arguments, char* environmentVariables, nint standardInput, nint standardOutput, nint standardError, ProcessStartInfo processStartInfo)
        {
            Arguments = arguments;
            EnvironmentVariables = environmentVariables;
            StandardInput = standardInput;
            StandardOutput = standardOutput;
            StandardError = standardError;
            ProcessStartInfo = processStartInfo;
        }

        /// <summary>
        /// Gets a pointer to the command-line arguments for the process.
        /// This is a pointer to a null-terminated <see cref="char"/> string (the full command line including the executable).
        /// </summary>
        /// <remarks>
        /// The memory pointed to by this property is only valid for the duration of the callback invocation.
        /// </remarks>
        [CLSCompliant(false)]
        public unsafe char* Arguments { get; }

        /// <summary>
        /// Gets a pointer to the environment variables block for the new process.
        /// This is a pointer to a null-terminated <see cref="char"/> string in the format used by CreateProcess
        /// (each variable is "name=value\0", terminated by an extra '\0').
        /// </summary>
        /// <remarks>
        /// The memory pointed to by this property is only valid for the duration of the callback invocation.
        /// This block is UTF-16; if passed to CreateProcess, include CREATE_UNICODE_ENVIRONMENT.
        /// </remarks>
        [CLSCompliant(false)]
        public unsafe char* EnvironmentVariables { get; }

        /// <summary>
        /// Gets the raw handle to use as the standard input for the new process.
        /// </summary>
        public nint StandardInput { get; }

        /// <summary>
        /// Gets the raw handle to use as the standard output for the new process.
        /// </summary>
        public nint StandardOutput { get; }

        /// <summary>
        /// Gets the raw handle to use as the standard error for the new process.
        /// </summary>
        public nint StandardError { get; }

        /// <summary>
        /// Gets the original <see cref="ProcessStartInfo"/> provided by the user,
        /// allowing the callback to inspect any additional configuration.
        /// </summary>
        public ProcessStartInfo ProcessStartInfo { get; }

        /// <summary>
        /// Starts a new process by preparing all necessary arguments (standard handles, command line, environment)
        /// and then invoking the user-supplied <paramref name="callback"/> to perform the actual process creation system call.
        /// The callback receives a <see cref="WindowsProcessStartArguments"/> instance with the prepared data and must return an
        /// <see cref="nint"/> representing the handle of the created process.
        /// </summary>
        /// <param name="startInfo">The <see cref="ProcessStartInfo"/> that contains the information used to start the process.</param>
        /// <param name="callback">
        /// A function that receives the prepared <see cref="WindowsProcessStartArguments"/> and creates the process using any system call of the user's choice.
        /// The callback must return a valid process handle (<see cref="nint"/>) for the newly created process.
        /// The memory referenced by pointer properties in <see cref="WindowsProcessStartArguments"/> is only valid for the duration of the callback.
        /// The callback is invoked while an internal process-start lock is held; calling System.Diagnostics.Process APIs that start processes from within the callback may deadlock or throw.
        /// </param>
        /// <returns>A new <see cref="Process"/> instance associated with the started process.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="startInfo"/> or <paramref name="callback"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException">The <see cref="nint"/> returned by the callback is invalid.</exception>
        /// <exception cref="InvalidOperationException"><see cref="ProcessStartInfo.UseShellExecute"/> is set to <see langword="true"/>.</exception>
        [SupportedOSPlatform("windows")]
        public static Process Start(ProcessStartInfo startInfo, Func<WindowsProcessStartArguments, nint> callback)
        {
#if !TARGET_WINDOWS
            throw new PlatformNotSupportedException();
#else
            ArgumentNullException.ThrowIfNull(startInfo);
            ArgumentNullException.ThrowIfNull(callback);

            if (startInfo.UseShellExecute)
            {
                throw new InvalidOperationException(SR.Format(SR.UseShellExecuteNotSupportedForScenario, nameof(Start)));
            }

            Process process = new();

            try
            {
                process.StartCoreWithCallback(startInfo, callback);
            }
            catch
            {
                process.Dispose();

                throw;
            }

            return process;
#endif
        }
    }
}