7

This is my problem. I have a program that has to run in a TTY, cygwin provides this TTY. When I redirect stdIn the program fails because it does not have a TTY. I cannot modify this program, and need some way of automating it.

How can I grab the cmd.exe window and send it data and make it think the user is typing it?

I'm using C#, I believe there is a way to do it with java.awt.Robot but I have to use C# for other reasons.

David Basarab
  • 72,212
  • 42
  • 129
  • 156
Malfist
  • 31,179
  • 61
  • 182
  • 269
  • see also the other question about this: http://stackoverflow.com/questions/450741/getting-the-pipe-from-rsync-to-run-as-a-script – David Schmitt Jan 16 '09 at 17:27
  • that was my other question, I decided to try a different way, hence a different question – Malfist Jan 16 '09 at 17:31

4 Answers4

5

I have figured out how to send the input to the console. I used what Jon Skeet said. I am not 100% sure this is the correct way to implement this.

If there are any comments on to make this better I would love to here. I did this just to see if I could figure it out.

Here is the program I stared that waited for input form the user

class Program
{
    static void Main(string[] args)
    {
        // This is needed to wait for the other process to wire up.
        System.Threading.Thread.Sleep(2000);

        Console.WriteLine("Enter Pharse: ");

        string pharse = Console.ReadLine();

        Console.WriteLine("The password is '{0}'", pharse);


        Console.WriteLine("Press any key to exit. . .");
        string lastLine = Console.ReadLine();

        Console.WriteLine("Last Line is: '{0}'", lastLine);
    }
}

This is the console app writing to the other one

class Program
{
    static void Main(string[] args)
    {
        // Find the path of the Console to start
        string readFilePath = System.IO.Path.GetFullPath(@"..\..\..\ReadingConsole\bin\Debug\ReadingConsole.exe");

        ProcessStartInfo startInfo = new ProcessStartInfo(readFilePath);

        startInfo.RedirectStandardOutput = true;
        startInfo.RedirectStandardInput = true;
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.CreateNoWindow = true;
        startInfo.UseShellExecute = false;

        Process readProcess = new Process();
        readProcess.StartInfo = startInfo;

        // This is the key to send data to the server that I found
        readProcess.OutputDataReceived += new DataReceivedEventHandler(readProcess_OutputDataReceived);

        // Start the process
        readProcess.Start();

        readProcess.BeginOutputReadLine();

        // Wait for other process to spin up
        System.Threading.Thread.Sleep(5000);

        // Send Hello World
        readProcess.StandardInput.WriteLine("Hello World");

        readProcess.StandardInput.WriteLine("Exit");

        readProcess.WaitForExit();
    }

    static void readProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        // Write what was sent in the event
        Console.WriteLine("Data Recieved at {1}: {0}", e.Data, DateTime.UtcNow.Ticks);
    }
}
David Basarab
  • 72,212
  • 42
  • 129
  • 156
1

Can you start the program (or cygwin) within your code, using ProcessStartInfo.RedirectStandardInput (and output/error) to control the data flow?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I can start it with it. But once it get's the the point where the program has to have the TTY it fails. The program asks for a password, and modifies the TTY to hide the keystrokes. It cannot do this with a redirected stream so it fails. – Malfist Jan 16 '09 at 17:20
1

This sounds like a task for SendKeys(). It's not C#, but VBScript, but nontheless - you asked for some way of automating it:

Set Shell = CreateObject("WScript.Shell")

Shell.Run "cmd.exe /k title RemoteControlShell"
WScript.Sleep 250

Shell.AppActivate "RemoteControlShell"
WScript.Sleep 250

Shell.SendKeys "dir{ENTER}"
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • I was actually looking at SendKeys already. SendKey's is part of the .NET 2.0 framework so I can use it from C#. I'll see if this works. – Malfist Jan 16 '09 at 17:40
  • 1
    Using the SendKeys class basically requires you to make the TTY active - then you just call SendKeys.Send and it sends the keystrokes. – Jon Skeet Jan 16 '09 at 17:50
  • But it's not working, occasionally it will send one key, and that's it. I think I may ask another question about sendkey's if I cannot get it working soon. – Malfist Jan 16 '09 at 18:04
  • Okay, the problem was I was losing focus, that is fixed now. – Malfist Jan 16 '09 at 18:09
  • See also http://stackoverflow.com/questions/6838363/win32-equivalent-of-net-sendkeys for a C++ equivalent to SendKeys. When Jon Skeet said "make active" I believe he's referring to the AppActive which "brings an application's window into focus." Apparently there's no reliable way to just send messages to a window http://stackoverflow.com/questions/1220820/how-do-i-send-key-strokes-to-a-window-without-having-to-activate-it-using-window – rogerdpack Jun 23 '15 at 00:16
0

I had similar problem some time ago, cygwin should write some useful information (exact cygwin function, error text and WINAPI error code) to error stream, you should redirect it somewhere and read what it writes.

okutane
  • 13,754
  • 10
  • 59
  • 67
  • no, cygwin writes _everything_ to the StandardErrorStream. The error is about ioclt inappropriate for the device meaning I need a real TTY for it to be used. – Malfist Jan 16 '09 at 17:50
  • bash: [####: #] tcsetattr: Inappropriate ioctl for device – Malfist Jan 16 '09 at 18:05