Redirect CMD.exe output to a pipe - winapi

Can I use CreateProcess (or ShellExecute, or any other means of invoking cmd.exe to run a batch script) and have all output redirected to a pipe owned by my process? How do I give the child cmd.exe process a handle to one of the pipe endpoints? Is it even possible to use a pipe in this way?
(Googling for variations on the terms "cmd.exe" and "pipes" is nothing but redirecting output to another program using the |(pipe) character)

Here's how you would do it with .NET: http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx
And for C/C++: http://msdn.microsoft.com/en-us/library/ms682499(v=VS.85).aspx

Probably this will help... it is in VB.NET but it shouldn't be hard to change it to C#...
http://blogs.msdn.com/b/rahulso/archive/2006/04/01/run-a-command-from-the-command-prompt-and-get-its-output-in-a-windows-application.aspx

Related

Why can't I redirect stdout/err of a program run by a batch file, called by another batch?

If I have this batch:
ScriptA.bat
someprog.exe
And this one:
ScriptB.bat
CALL ScriptA.bat
And I execute a command like:
ScriptB.bat > test.log
The output from someprog.exe is not logged. It flows through to the console. How can I avoid having to explicitly pipe the output of someprog.exe to a file, and instead just capture that from a higher level?
(Note I ultimately want to do this with a great many scripts launching assorted exes from inside those nesting, and I can't edit them all to redirect the output of each and every sub process they invoke).
I found the answer to this on another SO thread:
https://stackoverflow.com/a/11955380/3220983
As you'll see if reading the comments under the question, the problem I was encountering was that the messages I couldn't capture were not being piped to stdout or stderr at all! They were going straight to the console via something akin to a CON redirect from inside the specific executable I was trying to use.
The link I posted shows how to launch a PowerShell script from a batch script, which captures the entire console window contents, inclusive of CON output!

Is it possible to obtain the _raw_/_unprocessed_ command line?

The windows API provides GetCommandLine() which returns the cooked command line used to start a process.
For instance, if a console application is started with the command:
MyProg.exe > OutputHere
The command line seen by MyProg.exe will not include the portion
> OutputHere
I'd like to somehow get the command line exactly as it was. Is this possible ? and if yes, how ?
Suggestions in C and/or plain (no objects) Delphi greatly appreciated. Creative solutions welcome (hopefully, not requiring ring 0 code.)
Thank you very much for your help.
NOTE: I can tell if the input/output, etc has been redirected but, that is not what I'm looking for. I need the original/uncooked command line.
The redirection or piping of stdin, stdout and stderr is handled the command interpreter, typically cmd.exe. The interpreter parses the command and creates the necessary files and pipes, and then creates the one or more processes needed to implement your command.
The processes that are created have no knowledge of the original command, they only get that part of the command that is not related to piping and redirection.
So what you are trying to do is not possible, at least within your process. The only thing that knows the original command is the command interpreter.
Whether or not you can retrieve the full command line including the pipe commands depends on whether your start the program in a command window or for example using the "Run" command from the Start menu. If you use the "Run" command from the Start menu GetCommandLine actually retrieves the full command line including the redirection commands, but redirection does not work as it seems to be a feature of CMD.EXE.
As others have pointed out, what are you trying to achieve here / why do you need to capture the redirection commands?

Redirecting cmd stdout and stderr back to parent

If I create a process from a cmd prompt using the start command (opening a new cmd) is it possible to redirect the stdout and stderr from that process back to the calling cmd?
If you want the output of the STARTed process to appear in the parent command console, then simply use the START /B option.
If you want to process the output of your command, then you should use FOR /F ... in ('someCommand') DO ... instead.
OK. I have yet to find a straightforward answer to this question. I didn't want to bog down my question with what I thought unnecessary detail but seeing as I'm being criticized for the lack of this I'll expand a bit here.
I want to automate the updating of FWs on our production line, so I've a python app that gets the FWs from ftp and then uses the processors flash tool via python subprocess command to upload it to the board's flash. OK for all but one of the tools.
The one tool seems to have a problem when it's not running in its own terminal, so I provide a start to the subprocess command string which allows it to run OK in its own terminal. However, I need the output from this other terminal for logging reasons.
A possible solution was to log stdout and stderr to file using >> or wintee and then poll this file via a thread in my original app (perhaps a rather convoluted solution to the question). However the tool also has a separate problem where it doesn't like any std redirection, so this doesn't work for me.

Run a simple shell command

What is the best WinAPI function to use when you only want to run a simple shell command like hg > test.txt?
To simply run a file, then ShellExecute() and CreateProcess() are the best options.
As you want to redirect output to a file/run a shell command, it complicates things...
Output redirection is a feature of the command prompt, and as such, the command you want to run needs to be passed to cmd.exe (on NT/XP+) passing /c and your command as the parameters (either ShellExecute or CreateProcess will do).
cmd /c "ipconfig >c:\debug\blah.txt"
The best way however is to use CreateProcess() and create your own pipes to talk to the stdin and stdout of the program (This is all cmd does internally)
You could use ShellExecute(), but why not try system() first? I am not so sure that ShellExecute() can actually do piping or redirection. There is also CreateProcess(), but that requires a bit more work. CreateProcess() gives you the best control, though.
There are two ways of issuing commands: the Windows Shell way, and the command line way.
Windows Shell issues commands by executing verbs on files. Verbs are associated with file types in the registry. Examples of common verbs are Open and Print. The WinAPI to use for this is ShellExecute. Windows Shell does not help you pipe the output of a process to a file. You can do it using CreateProcess, but it is a little bit involved.
The command line way is to use the system function.

Continue capturing output after redirection

Okay, here's a toughie-- I'm capturing the output of cmd.exe just fine, reading from the pipe, yadda yadda yadda, but then a line in the cmd.exe batch file has the audacity to do:
dir err.txt >zz
.. that is, it's redirecting the output of the dir command, which is an internal command inside cmd.exe.
Problem is, this breaks my capturing of output! I can't get anything from cmd.exe after that point.
Apparently to redirect standard output, it closes it, or somehow breaks it, and makes a new stdout to redirect the output. And it never restores the old stdout handle.
Any ideas of how to track this output?
If you are allowed to modify the batch file, you may replace the inner redirection by a TEE command.
There are several ports to Windows (just google "windows command tee").
From Wikipedia:
In computing, tee is a command in various command-line interpreters (shells)
such as Unix shells, 4DOS/4NT and Windows PowerShell, which displays or pipes
the output of a command and copies it into a file or a variable
you should call dir err.txt in a separate process. try call dir err.txt >zz

Resources