2

Fetching standard output is easy if Process.StartInfo.UseShellExecute = false. However, in my case, UseShellExecute must remain true. The reason is that I am kicking off an .exe that happens to be in the PATH but not in the current working directory.

Here is the reason I can't use UseShellExecute = false:

var psi = new ProcessStartInfo("cleancss", "--help")
{
    WorkingDirectory = @"C:\SomeRandomDirectory",
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardInput = true
};

Process cssClean = Process.Start(psi);  //blows up with The system cannot find the file specified

It correctly blows up because UseShellExecute = false requires an absolute path. I do not have an absolute path.

If I set UseShellExecute = true in the above sample, it tells me that redirecting standard output doesn't work in this scenario.

How do I get the standard output when UseShellExecute is true?

AngryHacker
  • 59,598
  • 102
  • 325
  • 594
  • 1
    Note that there are ways of finding the full path to an executable that is in the PATH. See [Check if an executable exists in the Windows path](https://stackoverflow.com/q/3855956/215552). – Heretic Monkey Jun 05 '20 at 18:34

2 Answers2

0

If you do not give a absolute path Windows will:

  1. Look for a .bat, .exe, then .com file in the working directory that has "cleancss" before the dot (I am unsure about the exact order for those 3; nowadays it might include stuff like .VBS and other executables)

  2. Then go through the path variable entries, doing the same check for every one of them

  3. The fist thing it finds, it executes

  4. If it failed and is through the entire path list, only then will it admit to failure

(Note there is a 0 for Windows/DOS Console: "Check if that is a reserved keyword I should react to myself". Over the decades programs kept shifting from Keyword to dedicated process and back again).

Ideally you should have this path set in the Application Settings - whatever way to persist application settings you are using. You can then optionally give the user a UI to set that path. Having Windows figure out which file you even mean is so DOS era. Where we had no options like the registry. Or Find File Dialogs. It should not be in use in 2020.

If you somehow have to keep at that (or you need to find a default), it would be trivial to implement Windows search pattern. Try all 3 extensions in the planned working directory. The retrieve the path variable and iterate over it.

In the end, every program call in Windows uses a absolute path. Just sometimes Windows has to figure out the absolute path for you, because you are a stupid normal user that typed "EDIT" while far away from from the System directory.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Christopher
  • 9,634
  • 2
  • 17
  • 31
0

You can start the CMD.exe your self with the /c argument followed by what you want to execute. Cmd doesn't need a path but if started it does inherit the environment from its caller and does have a fully populated PATH.

var psi = new ProcessStartInfo("cmd", "/c cleancss --help")
{
    WorkingDirectory = @"C:\SomeRandomDirectory",
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardInput = true
};

Process cssClean = Process.Start(psi);  

The /c parameter of cmd.exe is described as:

Carries out the command specified by string and then terminates

In my testing any output from what is started this way gets pipe-d to the parent process.

rene
  • 41,474
  • 78
  • 114
  • 152