ShellExecute: Verb “runas” does not work for batch

2020-03-28 01:40发布

问题:

I am using ShellExecuteW to start a batch file. Code looks somewhat like this:

ShellExecuteW(GetDesktopWindow(), wide_verb.c_str(), wide_filename.c_str(), wide_parameters.c_str(), NULL, SW_SHOW);

Where the wide_ variables are of type wstring. This code works fine for arbitrary combinations of file path and verb, except for verb "runas" (to get administrator rights) and a batch file with spaces in the given path wide_filename. The UAC prompt will pop up and, after confirmation, for a short moment the command prompt will flash up saying that the path could not be found, cutting off at the first space in the path.

I already tried wrapping the file name in additional quotes, but that didn't help.

The reason is probably that .bat files aren't really "executables", but documents, and therefor

ShellExecuteW(GetDesktopWindow(), L"runas", L"C:\\Path To\\file.bat", L"Parameters For Batch", NULL, SW_SHOW);

is internally mapped to an elevated execution of

cmd.exe /C "C:\Path To\file.bat" "Parameters for Batch"

while it should be something along the lines of

cmd.exe /S /C " "C:\Path To\file.bat" Parameters for Batch "

And indeed, if I execute something like this:

ShellExecuteW(GetDesktopWindow(), L"runas", L"cmd.exe", L"/S /C \" \"C:\\Path To\\file.bat\" Parameters For Batch \"", NULL, SW_SHOW);

it does the trick!

However, it doesn't seem like the cleanest approach to "hardcode" the executable (cmd.exe in this case) like that. For batch files it really doesn't matter, but for other script-type documents that take parameters it might become relevant.

So the question is: Is it possible to execute a batch file (with spaces in its path) elevated via ShellExecute or a similar mechanism, without explicitly passing it to cmd.exe?

回答1:

CreateProcessWithLogonW is what you need here. It has a lot of arguments, but at the end of the page you'll see an Examples section instructing how to initialize the args.

As for hardcoding cmd.exe here's what CreateProcess official doc says (at the end of the section describing the lpApplicationName argument):

To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.

So i think you're good. Of course the path enclosing in "s still applies.