Starting a .NET process with CreateProcessW using lpApplicationName ends up in messed up commandline args
MichalPetryka opened this issue · comments
Description
Starting a .NET process with CreateProcessW
using lpApplicationName
for the executable results in all the args APIs in .NET treating the 1st commandline arg as the executable name and skipping it for Main
args. The real executable name isn't present anywhere.
I'm not sure how exactly does using CreateProcessW
like this affect the OS APIs but on the managed side this behaviour is counterintuitive.
Reproduction Steps
Launch this code with CreateProcessW by passing the executable in lpApplicationName
and some args like "123":
Console.WriteLine(JsonSerializer.Serialize(args));
Console.WriteLine(JsonSerializer.Serialize(Environment.GetCommandLineArgs()));
Console.WriteLine(JsonSerializer.Serialize(Environment.CommandLine.Split(' ')));
Expected behavior
Outputs:
[
"123"
]
[
"ConsoleApp1.exe",
"123"
]
[
"ConsoleApp1.exe",
"123"
]
Actual behavior
Outputs:
[]
[
"123"
]
[
"123"
]
Regression?
Doesn't seem so, .NET Framework behaves the same.
Known Workarounds
Don't use lpApplicationName
, pass the executable in lpCommandLine
instead.
Configuration
.NET 9
Windows 10.0.19045 x64
Other information
No response
There likely isn't anything for .NET to do here and this is instead a quirk of how native works.
If you use the lpApplicationName
parameter then it isn't part of the lpCommandLine
.
It could potentially try and detect if the executable is part of the command line, but that might not be possible or trivial to do, especially not without cost.
I expect that you would see identical behavior in C/C++
Tagging subscribers to this area: @vitek-karas, @agocke, @VSadov
See info in area-owners.md if you want to be subscribed.
You are expected to include the executable name in the lpCommandLine
argument for CreateProcessA/W
. https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa suggests that by saying "Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.".
It is by design that the launched binary can be different from the argv[0] command line arguments. It allows Unix-like tricks like having multiple commands all pointing to the same binary. We have actually regressed this behavior in .NET Core and these tricks are not possible in .NET Core today. #101837 tracks fixing this regression.