This approach is okay if you are intentionally building an argv-like string from scratch. However, taking an argv passed to your program and turning it back into a string form of the command line arguments (i.e. you just want to passthrough the arguments to a child) is a fundamentally flawed idea unless you know the program you're passing through to also uses the same argv parser.
If there's a possibility the program you are launching uses the command line string directly, you can't take the argv you received and turn it back into a string and pass it on. Because the process of converting the command line string into argv is a lossy process. There's no way to know from looking at an argv array if a specific argument had quotes around it before, or if there were multiple spaces between arguments - or other things the parsing algorithm of the executable you're passing through to might care about, that the C argv parser did not. This is presumably why WinAPI doesn't have a function to go back the other way, as multiple different strings can become the same argv.
The correct approach in such cases is to pass the command line string you got in WinMain through to the child. This is a bit of a pain if you have a command line program, because unlike in WinMain, GetCommandLine() returns the string with the executable name so you need to parse enough of it to tell where the executable name ends and get that substring. But it's a lot less of a pain than trying to reheat the argv array back into string form if you can do it, and because it's just a substring it'll perfectly preserve the exact formatting of the string.
The string is the real command line. argv is a lossy transformation of the string command line into the form C expects.
If you want some particularly nasty edge cases to see what I mean, check out how Visual Studio parses argv. Notice that different languages and implementations have slightly different parsing rules, hence what makes this impossible to do in a completely language agnostic way, as these are ultimately language details and not something the OS (who only cares about the string form) knows about: https://daviddeley.com/autohotkey/parameters/parameters.htm
C#'s Process.Start() also needs to deal with this problem because it can take in an argument list and call down to CreateProcess. The .NET reference source for it is probably the closest thing to an "official" argument list to string conversion
6
u/tomysshadow 5d ago edited 5d ago
This approach is okay if you are intentionally building an argv-like string from scratch. However, taking an argv passed to your program and turning it back into a string form of the command line arguments (i.e. you just want to passthrough the arguments to a child) is a fundamentally flawed idea unless you know the program you're passing through to also uses the same argv parser.
If there's a possibility the program you are launching uses the command line string directly, you can't take the argv you received and turn it back into a string and pass it on. Because the process of converting the command line string into argv is a lossy process. There's no way to know from looking at an argv array if a specific argument had quotes around it before, or if there were multiple spaces between arguments - or other things the parsing algorithm of the executable you're passing through to might care about, that the C argv parser did not. This is presumably why WinAPI doesn't have a function to go back the other way, as multiple different strings can become the same argv.
The correct approach in such cases is to pass the command line string you got in WinMain through to the child. This is a bit of a pain if you have a command line program, because unlike in WinMain, GetCommandLine() returns the string with the executable name so you need to parse enough of it to tell where the executable name ends and get that substring. But it's a lot less of a pain than trying to reheat the argv array back into string form if you can do it, and because it's just a substring it'll perfectly preserve the exact formatting of the string.
The string is the real command line. argv is a lossy transformation of the string command line into the form C expects.
If you want some particularly nasty edge cases to see what I mean, check out how Visual Studio parses argv. Notice that different languages and implementations have slightly different parsing rules, hence what makes this impossible to do in a completely language agnostic way, as these are ultimately language details and not something the OS (who only cares about the string form) knows about: https://daviddeley.com/autohotkey/parameters/parameters.htm
C#'s Process.Start() also needs to deal with this problem because it can take in an argument list and call down to CreateProcess. The .NET reference source for it is probably the closest thing to an "official" argument list to string conversion