Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 4cdbe10

Browse files
authored
ArgumentList added to Process.StartInfo (#27191)
1 parent 0087308 commit 4cdbe10

14 files changed

+276
-14
lines changed

src/Common/src/System/PasteArguments.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System.Collections.Generic;
65
using System.Text;
76

87
namespace System
98
{
109
internal static partial class PasteArguments
1110
{
12-
private static void AppendArgument(StringBuilder stringBuilder, string argument)
11+
internal static void AppendArgument(StringBuilder stringBuilder, string argument)
1312
{
1413
if (stringBuilder.Length != 0)
1514
{

src/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ public ProcessStartInfo() { }
158158
public ProcessStartInfo(string fileName) { }
159159
public ProcessStartInfo(string fileName, string arguments) { }
160160
public string Arguments { get { throw null; } set { } }
161+
public System.Collections.ObjectModel.Collection<string> ArgumentList { get { throw null; } }
161162
public bool CreateNoWindow { get { throw null; } set { } }
162163
public string Domain { get { throw null; } set { } }
163164
[System.ComponentModel.DefaultValueAttribute(null)]

src/System.Diagnostics.Process/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,7 @@
315315
<data name="UserDoesNotExist" xml:space="preserve">
316316
<value>User with name '{0}' was not found.</value>
317317
</data>
318+
<data name="ArgumentAndArgumentListInitialized" xml:space="preserve">
319+
<value>Only one of Arguments or ArgumentList may be used.</value>
320+
</data>
318321
</root>

src/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
<Compile Include="System\Diagnostics\ThreadWaitReason.cs" />
4848
<Compile Include="System\Diagnostics\MonitoringDescriptionAttribute.cs" />
4949
<Compile Include="System\Collections\Specialized\StringDictionaryWrapper.cs" />
50+
<Compile Include="..\..\Common\src\System\PasteArguments.cs">
51+
<Link>Common\System\PasteArguments.cs</Link>
52+
</Compile>
5053
</ItemGroup>
5154
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' and '$(TargetGroup)' != 'uap'">
5255
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.EnumProcessModules.cs">

src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,15 +376,14 @@ private bool StartCore(ProcessStartInfo startInfo)
376376
/// <summary>Size to use for redirect streams and stream readers/writers.</summary>
377377
private const int StreamBufferSize = 4096;
378378

379-
380379
/// <summary>Converts the filename and arguments information from a ProcessStartInfo into an argv array.</summary>
381380
/// <param name="psi">The ProcessStartInfo.</param>
382381
/// <param name="alternativePath">alternative resolved path to use as first argument</param>
383382
/// <returns>The argv array.</returns>
384383
private static string[] ParseArgv(ProcessStartInfo psi, string alternativePath = null)
385384
{
386385
string argv0 = psi.FileName; // when no alternative path exists, pass filename (instead of resolved path) as argv[0], to match what caller supplied
387-
if (string.IsNullOrEmpty(psi.Arguments) && string.IsNullOrEmpty(alternativePath))
386+
if (string.IsNullOrEmpty(psi.Arguments) && string.IsNullOrEmpty(alternativePath) && psi.ArgumentList.Count == 0)
388387
{
389388
return new string[] { argv0 };
390389
}
@@ -398,8 +397,16 @@ private static string[] ParseArgv(ProcessStartInfo psi, string alternativePath =
398397
argvList.Add("openURL"); // kfmclient needs OpenURL
399398
}
400399
}
400+
401401
argvList.Add(argv0);
402-
ParseArgumentsIntoList(psi.Arguments, argvList);
402+
if (!string.IsNullOrEmpty(psi.Arguments))
403+
{
404+
ParseArgumentsIntoList(psi.Arguments, argvList);
405+
}
406+
else
407+
{
408+
argvList.AddRange(psi.ArgumentList);
409+
}
403410
return argvList.ToArray();
404411
}
405412

src/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,21 @@ private unsafe bool StartWithShellExecuteEx(ProcessStartInfo startInfo)
4646
if (startInfo._environmentVariables != null)
4747
throw new InvalidOperationException(SR.CantUseEnvVars);
4848

49+
string arguments;
50+
if (startInfo.ArgumentList.Count > 0)
51+
{
52+
StringBuilder sb = new StringBuilder();
53+
Process.AppendArguments(sb, startInfo.ArgumentList);
54+
arguments = sb.ToString();
55+
}
56+
else
57+
{
58+
arguments = startInfo.Arguments;
59+
}
60+
4961
fixed (char* fileName = startInfo.FileName.Length > 0 ? startInfo.FileName : null)
5062
fixed (char* verb = startInfo.Verb.Length > 0 ? startInfo.Verb : null)
51-
fixed (char* parameters = startInfo.Arguments.Length > 0 ? startInfo.Arguments : null)
63+
fixed (char* parameters = arguments.Length > 0 ? arguments : null)
5264
fixed (char* directory = startInfo.WorkingDirectory.Length > 0 ? startInfo.WorkingDirectory : null)
5365
{
5466
Interop.Shell32.SHELLEXECUTEINFO shellExecuteInfo = new Interop.Shell32.SHELLEXECUTEINFO()

src/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,9 @@ private bool StartWithCreateProcess(ProcessStartInfo startInfo)
445445
// * CreateProcess allows you to redirect all or none of the standard IO handles, so we use
446446
// GetStdHandle for the handles that are not being redirected
447447

448-
StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments);
449-
448+
StringBuilder commandLine = BuildCommandLine(startInfo.FileName, StartInfo.Arguments);
449+
Process.AppendArguments(commandLine, StartInfo.ArgumentList);
450+
450451
Interop.Kernel32.STARTUPINFO startupInfo = new Interop.Kernel32.STARTUPINFO();
451452
Interop.Kernel32.PROCESS_INFORMATION processInfo = new Interop.Kernel32.PROCESS_INFORMATION();
452453
Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES();

src/System.Diagnostics.Process/src/System/Diagnostics/Process.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
// See the LICENSE file in the project root for more information.
44

55
using Microsoft.Win32.SafeHandles;
6-
using System.Collections.Generic;
6+
using System.Collections.ObjectModel;
77
using System.ComponentModel;
88
using System.Globalization;
99
using System.IO;
10-
using System.Security;
1110
using System.Text;
1211
using System.Threading;
1312

@@ -1198,6 +1197,10 @@ public bool Start()
11981197
{
11991198
throw new InvalidOperationException(SR.StandardErrorEncodingNotAllowed);
12001199
}
1200+
if (!string.IsNullOrEmpty(startInfo.Arguments) && startInfo.ArgumentList.Count > 0)
1201+
{
1202+
throw new InvalidOperationException(SR.ArgumentAndArgumentListInitialized);
1203+
}
12011204

12021205
//Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
12031206
if (_disposed)
@@ -1467,6 +1470,17 @@ internal void ErrorReadNotifyUser(String data)
14671470
}
14681471
}
14691472

1473+
private static void AppendArguments(StringBuilder stringBuilder, Collection<string> argumentList)
1474+
{
1475+
if (argumentList.Count > 0)
1476+
{
1477+
foreach (string argument in argumentList)
1478+
{
1479+
PasteArguments.AppendArgument(stringBuilder, argument);
1480+
}
1481+
}
1482+
}
1483+
14701484
/// <summary>
14711485
/// This enum defines the operation mode for redirected process stream.
14721486
/// We don't support switching between synchronous mode and asynchronous mode.

src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System.Collections;
66
using System.Collections.Generic;
7+
using System.Collections.ObjectModel;
78
using System.Collections.Specialized;
89
using System.ComponentModel;
910
using System.Text;
@@ -22,6 +23,7 @@ public sealed partial class ProcessStartInfo
2223
private string _directory;
2324
private string _userName;
2425
private string _verb;
26+
private Collection<string> _argumentList;
2527
private ProcessWindowStyle _windowStyle;
2628

2729
internal DictionaryWrapper _environmentVariables;
@@ -61,6 +63,18 @@ public string Arguments
6163
set => _arguments = value;
6264
}
6365

66+
public Collection<string> ArgumentList
67+
{
68+
get
69+
{
70+
if (_argumentList == null)
71+
{
72+
_argumentList = new Collection<string>();
73+
}
74+
return _argumentList;
75+
}
76+
}
77+
6478
public bool CreateNoWindow { get; set; }
6579

6680
public StringDictionary EnvironmentVariables => new StringDictionaryWrapper(Environment as DictionaryWrapper);

src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,7 @@ public void StartInfo_NotepadWithContent(bool useShellExecute)
987987
}
988988
}
989989
}
990+
990991
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer), // Nano does not support UseShellExecute
991992
nameof(PlatformDetection.IsNotWindows8x))] // https://github.com/dotnet/corefx/issues/20388
992993
[OuterLoop("Launches notepad")]

0 commit comments

Comments
 (0)