C# redirect input console application not working

1.3k views Asked by At

I have an interesting situation. I am trying to run a program from the command line and I cannot programatically redirect its input for some reason. The executable I am running is called. Spideroakone.exe. This executable asks for a password. When I type the password lets say the password is "asd" I can actually see what I am typing in plain text. I get an error message:

'asd' is not recognized as an internal or external command ...

If I run the executable like that :

cmd /c Spideroakone.exe

then again I see the same I am asked for a password. Then I type asd. But I can't see what I am typing and the password works and there is no error.

Now what I want to do is write an app that will execute Spideroak.exe and pass the password on the standard input. However because of the weird behaviour of Spideroak I am unable to pass any standard input to it nor I am able to read the standard output. When try to do that my app blocks on the writeline command. I would have expected to see the word "Password:" in the stdout. I have tried some async examples and multithreading but non of that works. The standard output buffer is always empty. I wonder what is this text I am seeing "Password:" if it is not written to the stdout where it is written?

this is the code I use. Which blocks on the ReadToEnd() line. This exact code works fine with a console app that I made so this makes me think the executable I am trying to execute is written in a weird way, but in a command line window it works fine:

Process myProcess = new Process();

myProcess.StartInfo.FileName = @"c:\windows\system32\cmd.exe";
myProcess.StartInfo.Arguments = @"/c ""C:\Program Files\SpiderOakONE\SpiderOakONE.exe"" --headless";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardInput = true;

myProcess.Start();

string s = myProcess.StandardOutput.ReadToEnd();
myProcess.WaitForExit();

This is the screenshot of the exact debug window and the line it blocks on:

This is what I see in the command line window:

1

There are 1 answers

2
Bisser Milanov On

Well no one responded and in the mean time I found the answer. I did not find the exact reason why stdout and stdin are not working but I read an article that someone else was complaining that old programs written in C using getch() will behave that way. I wanted to do it in a more pretty way but this is what I came up with. Basically sending key strokes to the console window. I wasn't sure if this will work because I am starting the process in Task Scheduler and there is no visual window created but it seems working fine.

I start the process in a separate thread:

new Thread(() =>
        {
        Process myProcess = new Process();

        myProcess.StartInfo.FileName = @"c:\windows\system32\cmd.exe";
        myProcess.StartInfo.Arguments = @"/c ""C:\Program Files\SpiderOakONE\SpiderOakONE.exe"" --headless";
        myProcess.StartInfo.UseShellExecute = false;
        myProcess.Start();

        myProcess.WaitForExit();
        }).Start();

Then I enumerate all windows:

EnumWindows(EnumTheWindows, IntPtr.Zero);

Then I look for the window of my process and send the desired key strokes to it. The Sleep in between is required without it is not working. The sample password I am sending is 'asd'

private static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
    {
        uint pidCurWindow;
        uint CurWindowThreadId = GetWindowThreadProcessId(hWnd, out pidCurWindow);
        int CurrentPID = System.Diagnostics.Process.GetCurrentProcess().Id;

        if (pidCurWindow == CurrentPID)
        {
            Thread.Sleep(50);
            PostMessage(hWnd, WM_KEYDOWN, VkKeyScan('a'), 0);
            Thread.Sleep(50);
            PostMessage(hWnd, WM_KEYDOWN, VkKeyScan('s'), 0);
            Thread.Sleep(50);
            PostMessage(hWnd, WM_KEYDOWN, VkKeyScan('d'), 0);
            Thread.Sleep(50);
            PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 1);
            Thread.Sleep(50);
        }
        return true;
    }

I hope this will help someone save time.