0

I'm writing trying to write a SSH client. Im using the windows forms NOT the console app. I dont want to use it becasue I want to learn how tog et this to work... Anyways onwards to the question. I have a while loop which is running as long as my shell is open. BUT in order to send input via my textbox to the Ssh server I need it to wait for input. I have added an event listener that listens for ENTER KEY. And to fetch then input i have a function which returns the data. Inside that function is a while loop, which is run as long as a variable is true. The whole thing about listing for enter was that i would change the varibale that keept the while inside my function running so that it exited that and returned the data inside the textbox.

So I need a way to overide the while loop inside the function and to set the variable to false. I hae heard about override aswell as the threading things but Im not sure on what to do.

Here's my code!

//Variables
public string mHost;
SshShell mShell;
public string mInput;
string pattern = "";
bool mInputHolder = true;

//Initiate form!
public Form1()
{
    InitializeComponent();

    txthost.Text = "sdf.org";
    txtuser.Text = "kalle82";
    txtpass.Text = "XXXX";
    string pattern = "sdf:";
    this.txtInput.KeyPress += new System.Windows.Forms.KeyPressEventHandler(checkforenter);
}

public void button1_Click(object sender, EventArgs e)
{
    try
    {
        mShell = new SshShell(Host, User);
        mShell.Password = Pass;
        //WRITING USER MESSAGE
        txtOutput.AppendText("Connecting...");
        mShell.Connect();
        txtOutput.AppendText("OK");
        //txtOutput.AppendText("Enter a pattern to expect in response [e.g. '#', '$', C:\\\\.*>, etc...]: ");
        //Stop for user input

        mShell.ExpectPattern = pattern;
        mShell.RemoveTerminalEmulationCharacters = true;

        while (mShell.ShellOpened)
        {
            txtOutput.AppendText("\r\n" + "TERMINAL MODE ENGAGED");
            txtOutput.AppendText(mShell.Expect( pattern ));
            string data = userInput();
            if (data == "") break;
            //Data from termninal --> Append to text
            string output = mShell.Expect(Pattern);
            txtOutput.AppendText(output);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

}

public void checkforenter(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
    if (e.KeyChar == (char)13)
    {
        mInputHolder = false;
    }
}

public string userInput()
{
    while (mInputHolder == true)
    {

    }
    mInputHolder = true;
    return txtInput.Text;
}
4

2 に答える 2

2

You may find it useful to make a class that extends TextReader and then set your Console.SetIn to that class. In the constructor of that class that you make have it have as a input parameter the textbox you want to to watch. From there use the overriden functions of TextReader to do what you need to do. No Whileloops, no Multithreading, no concurrent issues. That is just my 2 cents though. Here is SIMILAR article that shows to how to redirect Output. The concept is the same to redirect input.

http://saezndaree.wordpress.com/2009/03/29/how-to-redirect-the-consoles-output-to-a-textbox-in-c/

于 2012-05-08T18:33:01.797 に答える
1

Essentially your problem is unsolvable. If you block your code in a button click to wait for user input you will be freezing the UI, which will prevent anyone from being able to provide said input; this is called a deadlock.

You can open up the shell in the button click and then append to it later on after you have input, or you can wait until you already have the input to send to the shell before opening it in the first place.

Since you asked for some code, here's my 'hello world of a shell' example. I was actually using it to play around with WPF. There's a textbox for input, a textbox to display output, and a button to send the data in the input textbox to the shell. Realize that this is neither a production quality example, nor is it specifically written in response to your question, but it should demonstrate the overall approach to the problem.

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Process cmd;
        private bool scrollAtBottom = false;
        public MainWindow()
        {
            InitializeComponent();

            Closed+=new EventHandler(MainWindow_Closed);
            textBlock1.Text = "";

            textBox1.Focus();
        }

        private void button1_Click_1(object sender, RoutedEventArgs e)
        {
            if (cmd == null || cmd.HasExited)
            {
                cmd = new Process();
                cmd.StartInfo.CreateNoWindow = false;
                cmd.StartInfo.FileName = "cmd.exe";
                cmd.StartInfo.RedirectStandardInput = true;
                cmd.StartInfo.RedirectStandardOutput = true;
                cmd.StartInfo.UseShellExecute = false;

                cmd.OutputDataReceived += new DataReceivedEventHandler(cmd_OutputDataReceived);

                cmd.Start();
                cmd.BeginOutputReadLine();
            }

            cmd.StandardInput.WriteLine(textBox1.Text);

            textBox1.Text = "";
        }

        private void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            textBlock1.Dispatcher.Invoke(new Action(() =>
            {
                textBlock1.Text += e.Data + Environment.NewLine;
                scrollViewer1.ScrollToEnd();
            }));
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            if (cmd != null && !cmd.HasExited)
            {
                //exit nicely
                cmd.StandardInput.WriteLine("exit");
                if (!cmd.HasExited)
                {
                    //exit not nicely
                    cmd.Kill();
                }
            }
        }
    }
于 2012-05-08T18:39:06.340 に答える