问题
Let I want to write an application, that launches another application. Like this:
# This will launch another_app.exe
my_app.exe another_app.exe
# This will launch another_app.exe with arg1, arg and arg3 arguments
my_app.exe another_app.exe arg1 arg2 arg3
The problem here is that I'm getting char* argv[]
in my main
function, but I need to merge it to LPTSTR
in order to pass it to CreateProcess
.
There is a GetCommandLine
function, but I cannot use it because I'm porting code from Linux and tied to argc/argv
(otherwise, it's a very ugly hack for me).
I cannot easily merge arguments by hand, because argv[i]
might contain spaces.
Basically, I want the reverse of CommandLineToArgvW
. Is there a standard way to do this?
回答1:
The definitive answer on how to quote arguments is on Daniel Colascione's blog:
https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
I am reluctant to quote the code here because I don't know the license. The basic idea is:
for each single argument:
if it does not contain \t\n\v\",
just use as is
else
output "
for each character
backslashes = 0
if character is backslash
count how many successive backslashes there are
fi
if eow
output the backslashs doubled
break
else if char is "
output the backslashs doubled
output \"
else
output the backslashes (*not* doubled)
output character
fi
rof
output "
fi // needs quoting
rof // each argument
If you need to pass the command line to cmd.exe, see the article (it's different).
I think it is crazy that the Microsoft C runtime library doesn't have a function to do this.
回答2:
There is no Win32 API that does the reverse of CommandLineToArgvW()
. You have to format the command line string yourself. This is nothing more than basic string concatenation.
Microsoft documents the format for command-line arguments (or at least the format expected by VC++-written apps, anyway):
Parsing C++ Command-Line Arguments
Microsoft C/C++ startup code uses the following rules when interpreting arguments given on the operating system command line:
Arguments are delimited by white space, which is either a space or a tab.
The caret character (^) is not recognized as an escape character or delimiter. The character is handled completely by the command-line parser in the operating system before being passed to the argv array in the program.
A string surrounded by double quotation marks ("string") is interpreted as a single argument, regardless of white space contained within. A quoted string can be embedded in an argument.
A double quotation mark preceded by a backslash (\") is interpreted as a literal double quotation mark character (").
Backslashes are interpreted literally, unless they immediately precede a double quotation mark.
If an even number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is interpreted as a string delimiter.
If an odd number of backslashes is followed by a double quotation mark, one backslash is placed in the argv array for every pair of backslashes, and the double quotation mark is "escaped" by the remaining backslash, causing a literal double quotation mark (") to be placed in argv.
It should not be hard for you to write a function that takes an array of strings and concatenates them together, applying the reverse of the above rules to each string in the array.
回答3:
You need to recreate the command line, taking care of having all program name and arguments enclosed in "
. This is done by concatenating a \"
to these strings, one at the beginning, one at the end.
Assuming the program name to be created is argv[1]
, the first argument argv[2]
etc...
char command[1024]; // size to be adjusted
int i;
for (*command=0, i=1 ; i<argc ; i++) {
if (i > 1) strcat(command, " ");
strcat(command, "\"");
strcat(command, argv[i]);
strcat(command, "\"");
}
Use the 2nd argument of CreateProcess
CreateProcess(NULL, command, ...);
回答4:
You can check out the below code if it suits your need, the txt array sz can be used as a string pointer. I have added code support for both Unicode and MBCS,
#include <string>
#include <vector>
#ifdef _UNICODE
#define String std::wstring
#else
#define String std::string
#endif
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR sz[1024] = {0};
std::vector<String> allArgs(argv, argv + argc);
for(unsigned i=1; i < allArgs.size(); i++)
{
TCHAR* ptr = (TCHAR*)allArgs[i].c_str();
_stprintf_s(sz, sizeof(sz), _T("%s %s"), sz, ptr);
}
return 0;
}
来源:https://stackoverflow.com/questions/31838469/how-do-i-convert-argv-to-lpcommandline-parameter-of-createprocess