views:

80

answers:

3

My C Win32 application should allow passing a full command line for another program to start, e.g.

myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2"

myapp.exe may look something like

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
  // ...
}

I can think about some workarounds:

Both of them lengthy and re-implement cumbersome windows command line parsing logic, which is already a part of CommandLineToArgvW().

Is there a "standard" solution for my problem? A standard (Win32, CRT, etc.) implementation of workarounds counts as a solution.

+1  A: 

It's actually easier than you think.

1) There is an API, GetCommandLine() that will return you the whole string

myapp.exe /foo /bar "C:\Program Files\Some\App.exe" arg1 "arg 2"

2) CreateProcess() allows to specify the command line, so using it as

CreateProcess(NULL, "c:\\hello.exe arg1 arg2 etc", ....) 

will do exactly what you need.

3) By parsing your command line, you can just find where the exe name starts, and pass that address to the CreateProcess() . It could be easily done with

char* cmd_pos = strstr(GetCommandLine(), argv[3]);

and finally: CreateProcess(NULL, strstr(GetCommandLine(), argv[i]), ...);

EDIT: now I see that you've already considered this option. If you're concerned about performance penalties, they are nothing comparing to process creation.

ruslik
`strstr()`-like part is problematic. How about this use case: `myapp.exe /SetTitle C:\app.exe /RunMinimized C:\app.exe /ArgToApp.exe`. The actual command starts from the second match.
Ilia K.
@Ilia I see, in this case you should parse it by yourself. Anyway, don't boether about speed.
ruslik
A: 

I think it's actually harder than you think for a general case.

See http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx

It's ultimately up to the individual programs how they tokenize the command-line into an argv array (and even CommandLineToArgv in theory (and perhaps in practice, if what one of the comments said is true) could behave differently than the CRT when it initializes argv to main()), so there isn't even a standard set of esoteric rules that you can follow.

But anyway, the short answer is: no, there unfortunately is no easy/standard solution. You'll have to roll your own function to deal with quotes and backslashes and the like.

jamesdlin
A: 

The only standard function which you not yet included in your question is PathGetArgs, but it do not so much. The functions PathQuoteSpaces and PathUnquoteSpaces can be also helpful. In my opinion the usage of CommandLineToArgvW in combination with the with GetCommandLineW is what you really need. The usage of UNICODE during the parsing of the command line is in my opinion mandatory if you want to have a general solution.

Oleg