1

Im trying to build a cmd.exe wrapper but i cant figure out how to wait for a process inside the cmd process to finish.

When im run ping.exe in my program, my "inputline" (the path) will output to the console before the ping-command is finished.

I cant use: .WaitForInputIdle(); because I don't have a GUI. "This could be because the process does not have a graphical interface."

Is it even possible to solve or is there any better way to do it?

enter image description here

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ObjectTest
{
    class cmd
    {
        Process cmdProcess;
        StreamWriter cmdStreamWriter;

        public cmd()
        {
            //WinAPI.ShowConsoleWindow();
            Process();
            //WinAPI.HideConsoleWindow();
        }

        private void Process()
        {
            StartCmd();
            string command = "";
            while (command != "exit")
            {

                Thread.Sleep(100);
                cmdProcess.WaitForInputIdle();
                Console.Write(Environment.NewLine + Directory.GetCurrentDirectory() + "> ");
                command = Console.ReadLine();
                SendCommand(command);
            }
        }


        private void StartCmd()
        {
            cmdProcess = new Process();

            cmdProcess.StartInfo.FileName = "cmd.exe";
            cmdProcess.StartInfo.UseShellExecute = false;
            cmdProcess.StartInfo.CreateNoWindow = true;
            cmdProcess.StartInfo.RedirectStandardOutput = true;
            cmdProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
            cmdProcess.ErrorDataReceived += new DataReceivedEventHandler(SortOutputHandler);
            cmdProcess.StartInfo.RedirectStandardInput = true;
            cmdProcess.Start();

            cmdStreamWriter = cmdProcess.StandardInput;
            cmdProcess.BeginOutputReadLine();
        }

        private void SendCommand(string command)
        {
            cmdStreamWriter.WriteLine(command);
        }

        private void btnQuit_Click(object sender, EventArgs e)
        {
            cmdStreamWriter.Close();
            cmdProcess.WaitForExit();
            cmdProcess.Close();
        }

        private static void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!string.IsNullOrEmpty(outLine.Data))
            {
                Console.WriteLine(outLine.Data);
            }
        }


    }
}
Daniel Björk
  • 2,475
  • 1
  • 19
  • 26
  • Can't you start a batch file with the `cmd` process? That would start the commands in order and awaits the response. – Stefan May 26 '14 at 14:24
  • that wont help me. Ping.exe is just an example. I might want to run a dir command and then after reviewing the dir command i want to run multiple cd commands and so on. – Daniel Björk May 26 '14 at 14:27
  • 1
    could you tell us, clearly, what you are trying to do? (-1) – ctrl-alt-delor May 26 '14 at 14:30
  • @richard The first words of the question: "Im trying to build a cmd.exe wrapper". What's unclear? – Rotem May 26 '14 at 14:31
  • @richard whats unclear? Read the subject and the question... – Daniel Björk May 26 '14 at 14:32
  • so you want us to tell you how to build a cmd.exe wrapper. If we do that will you be happy? – ctrl-alt-delor May 26 '14 at 14:33
  • @richard, no i already built the wrapper but it doesnt behave like it should, mening it wont wait for the process within the process to finish before outputing the input row for next command. – Daniel Björk May 26 '14 at 14:35
  • It might be that its impossible to do what i want and then i want to know that, and why like i wrote in the question. "Is it even possible to solve or is there any better way to do it?" – Daniel Björk May 26 '14 at 14:38

2 Answers2

0

If it's only actual processes you want to catch you can use polling methods as such:

  1. Before running the command, collect all existing processes of, for example, ping (.exe), using Process.GetProcessesByName, and store their PIDs.

  2. Run the command

  3. In order to wait for exit, Again scan for all ping processes, and wait on all processes that did not previously exist.

Note that this will fail, or at least not be accurate, if another process will launch another ping between steps 1 and 3.

You should also keep in mind that CMD does not wait on all type of processes, only those which are defined as console applications (see this question).

Community
  • 1
  • 1
Rotem
  • 21,452
  • 6
  • 62
  • 109
-1

When starting a process, you can specify that you want to wait:

var process = Process.Start(...);
process.WaitForExit();

Here's a link to MSDN explaining it: http://msdn.microsoft.com/en-us/library/fb4aw7b8(v=vs.110).aspx

I think this is wat you need.

Complexity
  • 5,682
  • 6
  • 41
  • 84
  • It won´t work. Because that one is waiting for the cmd.exe to finish and not the ping.exe – Daniel Björk May 26 '14 at 14:23
  • 1
    And are you always going to execute the ping.exe command, otherwise you can start ping.exe instead of cmd.exe – Complexity May 26 '14 at 14:26
  • +1 for trying to answer a question, that has not enough info to be answered. – ctrl-alt-delor May 26 '14 at 14:28
  • no, I want to be able to use the cmd.exe as a cmd but with another input/output so i might send other commands. – Daniel Björk May 26 '14 at 14:28
  • So, as a comment in your original post i would suggest the following. Write a text file containing the command and save it as a bat file. Then let the bat file execute with WaitForExit(). That should do the trick. – Complexity May 26 '14 at 14:30
  • @Complexity then its not a cmd.exe wrapper. I want to run one command at a time and review the result before sending next command. – Daniel Björk May 26 '14 at 14:34
  • i might want to run cd.. and then dir and efter that cd "somedir" – Daniel Björk May 26 '14 at 14:37
  • @DanielBjörk are `cd`, `dir`, etc. actually separate processes? I'm not an expert on the CMD prompt, but I find it hard to believe. – Rotem May 26 '14 at 14:39
  • @Rotem your right, they are internal commands of the cmd. But not ping, net, tracert and othercommands I want to be able to use. – Daniel Björk May 26 '14 at 14:42
  • 2
    What you're trying to do is typically done with a PowerShell script for exactly the reasons that you're failing to accomplish it by wrapping a command shell. Rethink your strategy and what it is you're trying to accomplish exactly. – Markus May 26 '14 at 15:00