views:

432

answers:

4

I'm writing a (Win32 Console) program that wraps another process; it takes parameters as in the following example:

runas.exe user notepad foo.txt

That is: runas parses user and then will run notepad, passing the remaining parameters.

My problem is that argv is broken down into individual parameters, but CreateProcessAsUser requires a single lpszCommandLine parameter.

Building this command line is probably not as simple as just joining argv back together with spaces. Any pointers?

This is just an example. My first argument isn't actually a user name, and might have spaces in it. This makes manually parsing the result of GetCommandLine tricky.

Similarly, a naive concatenation of argv won't work, because it needs to deal with the case where the original arguments were quoted and might have spaces in them.

+6  A: 

Manually recombining them is hard:

You could try to re-combine them, I think it would work, but be sure to following the same command line escaping rules that windows has. This could be more than the trivial solution you're looking for.

Also if there are any parameters that have spaces in them, then you would want to join them to the string with quotes around them. Here is an example of a strange escaping rule: if you have --folderpath "c:\test\" then the last backslash has to be doubled --folderpath "c:\test\\".

If you are using MFC:

You can can get the value you want from your derived CWinApp's theApp.m_lpCmdLine. Note you could still access them the other way too with __argc, and __argv or CommandLineToArgvW.

If you are using Win32 only (even without a GUI):

You can get it from WinMain. Which can be your program's entry point.

Note you could still access them the other way too with __argc, and __argv or CommandLineToArgvW.

If you must use a console based application with main or wmain:

The Win32 API GetCommandLine seems to be the way to go. You would need to still parse this to get past the .exe name though. Take into account quotes around the exe name/path too. If there are no such quotes at the start, then just go to the next space for the start.

Brian R. Bondy
Concatenating argv with spaces seems to work; if argv[i] contains a space, I quote that particular value. I've tried a couple of obvious edge cases, and it looks good so far.
Roger Lipscombe
+3  A: 

You can use the GetCommandLine function.

Why not use 'WinMain' instead of 'main'? This should give you the string in the format you want.

Vulcan Eager
The result of the GetCommandLine call should be processed though before being passed to the next CreateProcess call. The first argument should be removed. Beware that the program name could be wrapped with double quotes.
hvintus
In this particular case, the first two arguments need to be removed - the name of the executable and also the user name.
Vulcan Eager
A: 

Provided you have a string allocated with enough space then use strcat on each item in the list. Yes, it is as simple as joining them back together with spaces.

Edit: Of course, you would need to enclose any items containing spaces within quotes.

Xetius
-1, no it isn't as simple.
avakar
For his example, yes it would. The caveat of surrounding any items containing spaces with quotes would see you right on this one...
Xetius
+1  A: 

There is Win32 API call that returns command line: GetCommandLine

David Elkind