0

I've been trying to get cmd.exe /c /v:on executed using ShellExecute and ShellExecuteEx. However, both methods only seem to accept one parameter, because when it encounters the /v:on, a The filename, directory name, or volume label syntax is incorrect. is shown under Windows 7.

This is the code i've tried and am currently messing with (without luck):

#include <windows.h>

int main()

{

    SHELLEXECUTEINFO info = {0};

    info.cbSize = sizeof(SHELLEXECUTEINFO);
    info.fMask = SEE_MASK_NOCLOSEPROCESS;
    info.hwnd = NULL;
    info.lpVerb = NULL;
    info.lpFile = "cmd.exe";
    info.lpParameters = "/c /v:on SET example=stackoverflow & ECHO '!example! & pause'";
    info.lpDirectory = NULL;
    info.nShow = SW_SHOW;
    info.hInstApp = NULL;

    ShellExecuteEx(&info);

//  wait for process to terminate
//  WaitForSingleObject(info.hProcess, INFINITE);

    return 0;

}
script'n'code
  • 345
  • 4
  • 17

1 Answers1

3

Since cmd.exe is an executable file, you should be using CreateProcess() instead of ShellExecuteEx() (which is just going to call CreateProcess() internally anyway, so get rid of the middle man).

In any case, this is not a ShellExecute() problem. If you open a cmd.exe window and enter your complete command line:

cmd /c /v:on SET example=stackoverflow & ECHO '!example! & pause'`

You get the exact same error, and more:

cmd /c /v:on SET example=stackoverflow & ECHO '!example! & pause'

The filename, directory name, or volume label syntax is incorrect.
'!example!
'pause'' is not recognized as an internal or external command, operable program or batch file.

The reason for the first error is because /v is a parameter of cmd.exe itself, not a separate command that /C can execute. Everything that follows /C (or /K) is a new command line, so it must be the last parameter specified when calling cmd.exe. This is stated in the documentation for /C (and /K):

If /C or /K is specified, then the remainder of the command line after the switch is processed as a command line

As such, /v:on is being interpreted as the first parameter of a new command line, and so it gets treated as a filename which obviously doesn't exist.

Swap the /V and /C parameters, and the first error goes away:

cmd /v:on /c SET example=stackoverflow & ECHO '!example! & pause'

'!example!
'pause'' is not recognized as an internal or external command, operable program or batch file.

Now, you will notice that !example! is not being expanded as expected. That is because you are not quoting the command-line, as the documentation for /C (and /K) says:

Note that multiple commands separated by the command separator '&&' are accepted for string if surrounded by quotes. Also, for compatibility reasons, /X is the same as /E:ON, /Y is the same as /E:OFF and /R is the same as /C. Any other switches are ignored.

So, wrap the command-line in quotes, and then !example! gets expanded:

cmd /v:on /c "SET example=stackoverflow & ECHO '!example! & pause'"

'stackoverflow
'pause'' is not recognized as an internal or external command, operable program or batch file.

And lastly, pause is not being interpreted correctly because you put it inside of the single quotes of the ECHO instead of outside as a separate command:

cmd /v:on /c "SET example=stackoverflow & ECHO '!example!' & pause"

'stackoverflow '
Press any key to continue . . .

And then you can drop the single quotes from ECHO:

C:\Users\Ryan>cmd /v:on /c "SET example=stackoverflow & ECHO !example! & pause"

stackoverflow
Press any key to continue . . .
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Oh my, you're right! (about the command not working under CMD)... sigh... Since you're mentioning CreateProcess.... i can say i've already tried it... passing one parameter is no problem, but additional pamameters are not treated as extra cmd.exe parameters, which is something i'm trying to do to enable DelayedExpansion (let alone any other non-cmd related command that can follow).. Atleast your posted solution works, from the CMD.. i yet have to try this with CreateProcess. I'll keep you posted! – script'n'code Oct 02 '17 at 23:14
  • What I said works equally well from both `ShellExecute()` and `CreateProcess()`. I tried them both, and they both worked. – Remy Lebeau Oct 02 '17 at 23:28
  • Well... i somehow ended up using ShellExecute after all, for the sake of code simplicity/readability. Furthermore, CreateProcess offers functions that aren't even needed for my goal, anyway. **BUT**... the culprit/cause (and solution) of the problem was more easy than i thought.. I basically had to swap the order of /c and /v:on .... if only i noticed this in time... Any(how/who); If i hadn't considered to post/ask my question on SO, i most likely wouldn't have figured it out by myself, anytime soon. So i'm very grateful for your contribution! :-) - Case closed i guess – script'n'code Oct 02 '17 at 23:34
  • Next time, when something doesn't work right, try reading the documentation first (in this case, `CMD.EXE /?` or [here](https://technet.microsoft.com/en-us/library/cc771320.aspx)) – Remy Lebeau Oct 02 '17 at 23:38
  • I understand where you're coming from, but you don't want to know how many browser tabs i had (and have) opened when i was looking for a solution... You may not believe it/me but i'm one of the few whom actually does RTFM. I always check those things first before even considering to post about it on the internet. Yet i'm grateful you took the time/effort/patience in showing me the 'light' ;-) oh, one of my favorite CMD resources also happens to be SS64.com and DosTips (of the latter, some well known and praised scripters are also member on SO). – script'n'code Oct 03 '17 at 00:09