将argv[]传递给CreateProcess()的方法

将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

我的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
     } 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;
    }