将argv[]传递给CreateProcess()的方法
我的C Win32应用程序应该允许传递另一个程序启动的完整命令行,例如将argv[]传递给CreateProcess()的方法,c,winapi,command-line-arguments,createprocess,C,Winapi,Command Line Arguments,Createprocess,我的C Win32应用程序应该允许传递另一个程序启动的完整命令行,例如 myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2" myapp.exe可能看起来像 int main(int argc, char**argv) { int i; for (i=1; i<argc; ++i) { if (!strcmp(argv[i], "/foo") { // handle /foo
myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2"
myapp.exe
可能看起来像
int main(int argc, char**argv)
{
int i;
for (i=1; i<argc; ++i) {
if (!strcmp(argv[i], "/foo") {
// handle /foo
} else if (!strcmp(argv[i], "/bar") {
// handle /bar
} else {
// not an option => start of a child command line
break;
}
}
// run the command
STARTUPINFO si;
PROCESS_INFORMATION pi;
// customize the above...
// I want this, but there is no such API! :(
CreateProcessFromArgv(argv+i, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
// use startup info si for some operations on a process
// ...
}
int main(int argc,char**argv)
{
int i;
对于(i=1;i
并找到对应于argv[i]的子字符串
写一些类似于中提到的内容
它们都很冗长,并且重新实现了繁琐的windows命令行解析逻辑,这已经是系统的一部分
我的问题有“标准”的解决方案吗?解决方法的标准(Win32、CRT等)实现算是一个解决方案。实际上比你想象的要容易
1) 有一个API,GetCommandLine()
将返回整个字符串
myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2"
2) CreateProcess()
允许指定命令行,以便将其用作
CreateProcess(NULL, "c:\\hello.exe arg1 arg2 etc", ....)
你需要什么就做什么
3) 通过解析命令行,您只需找到exe名称的起始位置,并将该地址传递给CreateProcess()
char* cmd_pos = strstr(GetCommandLine(), argv[3]);
最后:CreateProcess(NULL,strstr(GetCommandLine(),argv[i]),…);
编辑:现在我看到您已经考虑过这个选项。如果您担心性能损失,那么与进程创建相比,它们算不了什么。我认为这实际上比您想象的一般情况更难
看
最终取决于各个程序如何将命令行标记为argv
数组(甚至在理论上(或者在实践中,如果其中一条评论是真的话),当CRT将argv
初始化为main()
)时,它们的行为可能与CRT不同因此,甚至没有一套标准的深奥规则可以遵循
但无论如何,简短的回答是:不,不幸的是,没有简单/标准的解决方案。你必须使用自己的函数来处理引号和反斜杠之类的问题。你的问题中还没有包括的唯一标准函数是,但它没有太多。函数和也可以很有帮助。在我看来of与with的结合是您真正需要的。我认为,如果您想要有一个通用的解决方案,在命令行解析过程中必须使用UNICODE。我的解决方法如下:安装Visual Studio后,您可以找到一些用于创建C库的标准代码的副本。特别是如果您在VC\crt\src\stdargv.c中可以找到“wparse_cmdline”函数的实现,该函数根据GetCommandLineW API的结果创建argc和argv。我创建了此代码的扩展版本,该代码还创建了“cmdv”指针数组,在每个argv指针开始的位置指向原始字符串。然后,您可以根据需要对argv参数执行操作,并且当您希望将“rest”传递给CreateProcess时,您可以只传入cmdv[i]
此解决方案的优点是使用完全相同的解析代码,仍然像往常一样提供argv,并且允许您传递原始代码,而无需重新引用或转义。我也遇到了与您相同的问题。问题是,如果可以分离GetCommandLine()的结果,我们不需要解析整个字符串
,然后您可以将它们放在一起
根据微软的文档,你应该只考虑反斜杠和引号。
你可以找到他们的文件
然后,您可以调用Solve
来获取下一个参数起点
E.g.
"a b c" d e
First Part: "a b c"
Next Parameter Start: d e
我在中解决了这些示例,所以一定要担心兼容性。
通过递归调用Solve
函数,可以得到整个argv
数组
这是文件test.c
#include <stdio.h>
extern char* Solve(char* p);
void showString(char *str)
{
char *end = Solve(str);
char *p = str;
printf("First Part: ");
while(p < end){
fputc(*p, stdout);
p++;
}
printf("\nNext Parameter Start: %s\n", p + 1);
}
int main(){
char str[] = "\"a b c\" d e";
char str2[] = "a\\\\b d\"e f\"g h";
char str3[] = "a\\\\\\\"b c d";
char str4[] = "a\\\\\\\\\"b c\" d e";
showString(str);
showString(str2);
showString(str3);
showString(str4);
return 0;
}
下面是Solve
函数的所有源代码,文件findarg.c
/**
This is a FSM for quote recognization.
Status will be
1. Quoted. (STATUS_QUOTE)
2. Normal. (STATUS_NORMAL)
3. End. (STATUS_END)
Quoted can be ended with a " or \0
Normal can be ended with a " or space( ) or \0
Slashes
*/
#ifndef TRUE
#define TRUE 1
#endif
#define STATUS_END 0
#define STATUS_NORMAL 1
#define STATUS_QUOTE 2
typedef char * Pointer;
typedef int STATUS;
static void MoveSlashes(Pointer *p){
/*According to Microsoft's note, http://msdn.microsoft.com/en-us/library/17w5ykft.aspx */
/*Backslashes are interpreted literally, unless they immediately precede a double quotation mark.*/
/*Here we skip every backslashes, and those linked with quotes. because we don't need to parse it.*/
while (**p == '\\'){
(*p)++;
//You need always check the next element
//Skip \" as well.
if (**p == '\\' || **p == '"')
(*p)++;
}
}
/* Quoted can be ended with a " or \0 */
static STATUS SolveQuote(Pointer *p){
while (TRUE){
MoveSlashes(p);
if (**p == 0)
return STATUS_END;
if (**p == '"')
return STATUS_NORMAL;
(*p)++;
}
}
/* Normal can be ended with a " or space( ) or \0 */
static STATUS SolveNormal(Pointer *p){
while (TRUE){
MoveSlashes(p);
if (**p == 0)
return STATUS_END;
if (**p == '"')
return STATUS_QUOTE;
if (**p == ' ')
return STATUS_END;
(*p)++;
}
}
/*
Solve the problem and return the end pointer.
@param p The start pointer
@return The target pointer.
*/
Pointer Solve(Pointer p){
STATUS status = STATUS_NORMAL;
while (status != STATUS_END){
switch (status)
{
case STATUS_NORMAL:
status = SolveNormal(&p); break;
case STATUS_QUOTE:
status = SolveQuote(&p); break;
case STATUS_END:
default:
break;
}
//Move pointer to the next place.
if (status != STATUS_END)
p++;
}
return p;
}
strstr()
-like部分有问题。这个用例如何:myapp.exe/SetTitle C:\app.exe/runc:\app.exe/ArgToApp.exe
。实际的命令从第二个匹配开始。@Ilia我明白了,在这种情况下,你应该自己解析它。无论如何,不要担心速度。
/**
This is a FSM for quote recognization.
Status will be
1. Quoted. (STATUS_QUOTE)
2. Normal. (STATUS_NORMAL)
3. End. (STATUS_END)
Quoted can be ended with a " or \0
Normal can be ended with a " or space( ) or \0
Slashes
*/
#ifndef TRUE
#define TRUE 1
#endif
#define STATUS_END 0
#define STATUS_NORMAL 1
#define STATUS_QUOTE 2
typedef char * Pointer;
typedef int STATUS;
static void MoveSlashes(Pointer *p){
/*According to Microsoft's note, http://msdn.microsoft.com/en-us/library/17w5ykft.aspx */
/*Backslashes are interpreted literally, unless they immediately precede a double quotation mark.*/
/*Here we skip every backslashes, and those linked with quotes. because we don't need to parse it.*/
while (**p == '\\'){
(*p)++;
//You need always check the next element
//Skip \" as well.
if (**p == '\\' || **p == '"')
(*p)++;
}
}
/* Quoted can be ended with a " or \0 */
static STATUS SolveQuote(Pointer *p){
while (TRUE){
MoveSlashes(p);
if (**p == 0)
return STATUS_END;
if (**p == '"')
return STATUS_NORMAL;
(*p)++;
}
}
/* Normal can be ended with a " or space( ) or \0 */
static STATUS SolveNormal(Pointer *p){
while (TRUE){
MoveSlashes(p);
if (**p == 0)
return STATUS_END;
if (**p == '"')
return STATUS_QUOTE;
if (**p == ' ')
return STATUS_END;
(*p)++;
}
}
/*
Solve the problem and return the end pointer.
@param p The start pointer
@return The target pointer.
*/
Pointer Solve(Pointer p){
STATUS status = STATUS_NORMAL;
while (status != STATUS_END){
switch (status)
{
case STATUS_NORMAL:
status = SolveNormal(&p); break;
case STATUS_QUOTE:
status = SolveQuote(&p); break;
case STATUS_END:
default:
break;
}
//Move pointer to the next place.
if (status != STATUS_END)
p++;
}
return p;
}