0

我正在学习 C#,我正在创建一个简单的 WinForms 应用程序,它的作用是启动一个简单的 OpenVPN 客户端:

    void button_Connect_Click(object sender, EventArgs e)
    {
        var proc = new Process();
        proc.StartInfo.FileName = "CMD.exe";
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.WorkingDirectory = @"C:\Program Files (x86)\OpenVPN\bin";
        proc.StartInfo.Arguments = "/c openvpn.exe --config config.ovpn --auto-proxy";

        // set up output redirection
        proc.StartInfo.RedirectStandardOutput = true;
        proc.StartInfo.RedirectStandardError = true;
        // Input
        proc.StartInfo.RedirectStandardInput = true;

        // Other
        proc.EnableRaisingEvents = true;
        proc.StartInfo.CreateNoWindow = false;
        // see below for output handler
        proc.ErrorDataReceived += proc_DataReceived;
        proc.OutputDataReceived += proc_DataReceived;

        proc.Start();

        StreamWriter myStreamWriter = proc.StandardInput;
        proc.BeginErrorReadLine();
        proc.BeginOutputReadLine();

        proc.WaitForExit();
    }

    void proc_DataReceived(object sender, DataReceivedEventArgs e)
    {
        // output will be in string e.Data
        if (e.Data != null)
        {
            string Data = e.Data.ToString();
            if (Data.Contains("Enter Auth Username"))
            {
                myStreamWriter("myusername");
            }
            //MessageBox.Show(Data);
        }
    }

它现在所做的是将 CMD 的所有输出发送到我的程序,该程序根据输出运行命令。

我当前的问题是,我需要写入流。我使用myStreamWriterin proc_DataReceived,但是它不在同一个上下文中,所以它不起作用。

我收到以下错误:The name 'myStreamWriter' does not exist in the current context,这在该范围内显然不存在。

我该如何进行这项工作?获取/设置属性?就像我说的那样,我对 C# 很陌生,所以任何帮助都将不胜感激。

4

3 回答 3

2

在您的表单中,添加此字段:

public class Form1Whatevver: Form {
    private StreamWriter myStreamWriter;
}

然后在您的代码中:

proc.Start();

this.myStreamWriter = proc.StandardInput;

proc.BeginErrorReadLine();
proc.BeginOutputReadLine();

现在,myStreamWriter 将可用于proc_DataReceived()

void proc_DataReceived(object sender, DataReceivedEventArgs e)
    {
        // output will be in string e.Data
        if (e.Data != null)
        {
            string Data = e.Data.ToString();
            if (Data.Contains("Enter Auth Username"))
            {
                if (myStreamWriter != null) // Just in case
                {
                    myStreamWriter("myusername");
                }
            }
            //MessageBox.Show(Data);
        }
    }
于 2012-12-14T14:47:49.440 回答
1

您正在谈论的概念是范围而不是上下文。


您可以通过多种方式更改您的代码,以便您可以myStreamWriterproc_DataReceived.

可以说最简单的方法是将您希望实现的对象作为参数传递给函数。从未来多线程的角度来看,这通常是一种很好的方法,也是一种功能风格的驱动力。

    void proc_DataReceived(
        object sender, 
        DataReceivedEventArgs e,
        StreamWriter writer)
    {
        ...
        writer("myusername");
        ...
    }

然而proc_DataReceived,显然是一个事件处理程序,您可能不想更改函数的签名。


如果您myStreamWriter在类级别声明为私有成员变量,您将能够从类中的任何位置访问。这this是可选的但很好的形式。

class YourForm : Form
{
    private StreamWriter myStreamWriter;

    void button_Connect_Click(...
    {
        ...
        this.myStreamWriter = proc.StandardInput;
        ...
    }

    void proc_DataRecieved(...
    {
        ...
        this.myStreamWriter("myusername");
        ...

    }
}

StreamWriter除非您想从类/表单外部访问,否则不需要属性实现。

于 2012-12-14T14:43:33.977 回答
1

简单的快速修复是定义myStreamWriter为类中的一个字段(即在您的方法范围之外),然后从其中一个范围内实例化它:

private StreamWriter _myStreamWriter;

void button_Connect_Click(object sender, EventArgs e)
{
    // Do some stuff

    _myStreamWriter = proc.StandardInput;

    // Do some stuff
}

完成后,您应该可以在课堂上的任何地方使用它。

于 2012-12-14T14:55:22.537 回答