【问题标题】:Input Username to cmd Process输入用户名到cmd进程
【发布时间】:2011-03-09 07:10:54
【问题描述】:

在我的 Winform 应用程序中,我使用 cmd 进程执行一个 exe 文件。 exe文件需要在“输入用户名”和“输入密码”行输入用户名和密码。我无法输入用户名和密码,不知何故该过程仅退出并且仅不起作用。我还添加了对 ThreadState 和 WaitReason 的检查,但 process.Threads 中没有线程。我也需要输出。如果我在输入过程之前输入输出,那么它直到输入才会到达,如果我在输出之前输入输入,那么输入也不会被接受。只需始终接收相同的输出。这是代码:

        public bool StartOpenVPN()
    {
        bool installed = false;
        ProcessStartInfo processInfo = null;
        Process process = null;
        try
        {
            string command = "files\\openvpn --config files\\client.ovpn";
            Console.WriteLine("Command = " + command);

            processInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
            processInfo.UseShellExecute = false;
            processInfo.RedirectStandardInput = true;
            processInfo.RedirectStandardOutput = true;
            Console.WriteLine("Opening cmd");

            process = new Process();
            process.StartInfo = processInfo;
            process.Start();

            StreamWriter sw = process.StandardInput;
            sw.WriteLine("foo");
            sw.WriteLine("*baa");
            sw.Flush();
            sw.Close();

            process.BeginOutputReadLine();
            process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);

            Console.WriteLine("Finished cmd");
        }
        catch (Exception e)
        {
            Console.WriteLine("Errror Installing Tap Adapter : " + e.Message);
            Console.WriteLine(e.StackTrace);
        }
        finally
        {
            processInfo = null;
            if (process != null)
            {
                process.Close();
                process = null;
            }
        }
        return installed;
    }

    private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        string d = e.Data;

        if (!string.IsNullOrEmpty(d))
        {
            Console.WriteLine("Line = " + d);
        }
    }

我得到的唯一输出是:

Line = Wed Mar 09 12:33:00 2011 OpenVPN 2.1.1 i686-pc-mingw32 [SSL] [LZO2] [PKCS11] built on Feb 17 2010
Line = Wed Mar 09 12:33:00 2011 ERROR: could not read Auth username from stdin
Line = Wed Mar 09 12:33:00 2011 Exiting

为什么它不接受输入,甚至在输出中显示“输入用户名”行?我无法确定我哪里出错了,但它似乎在某个地方出错了。请帮我解决这个问题,我被严重卡住了,已经尝试了很多次,并且在此之后花了很多时间。

非常感谢任何帮助。

谢谢

@Fun Mun :这是更新的代码。它只是去 process_Exited 获取任何流输入/输出:

        private void initProcess()
    {
        processInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
        processInfo.UseShellExecute = false;
        processInfo.RedirectStandardInput = true;
        processInfo.RedirectStandardOutput = true;
        processInfo.WindowStyle = ProcessWindowStyle.Normal;

        process = new Process();
        process.StartInfo = processInfo;
        process.Exited += new EventHandler(process_Exited);
        return;
    }

    void process_Exited(object sender, EventArgs e)
    {
        Console.WriteLine("Into process_Exited....");
        processInfo = null;
        if (process != null)
        {
            sw = null;
            process.Close();
            process = null;
        }
    }

    public bool StartOpenVPN()
    {
        bool installed = false;
        try
        {
            Console.WriteLine("Command = " + command);

            Console.WriteLine("Opening cmd");

            initProcess();
            process.Start();

            sw = process.StandardInput;
            Console.WriteLine("Has Exited after SW = " + process.HasExited.ToString()); // RETURS FALSE BUT GOES TO process_Exited & for next line results is NullPointerException
            sw.WriteLine("foo");
            sw.WriteLine("*baa");
             //sw.Flush();
            //sw.Close();

            //process.BeginOutputReadLine();
            //process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
             while (process.HasExited == false)
             {
                 string d = process.StandardOutput.ReadLine();
                 Console.WriteLine("Line = " + d);
             }

            process.WaitForExit();
            Console.WriteLine("Finished cmd");
        }
        catch (Exception e)
        {
            Console.WriteLine("Errror Opening : " + e.Message);
            Console.WriteLine(e.StackTrace);
        }

        return installed;
    }

直到 process.BeginOutputReadLine(); & 输出处理程序没有被删除,它一直在等待(可能是为了进入),就像挂出一样。删除这两条输出线并添加 while 循环的那一刻,进程只会在任何流调用中退出,即 process.StandardOutput;或 StandardInput 以后者为准并抛出 NullPointerException。 我是否按照您的指示在代码中犯了任何错误?


@Fun Mum :即使在使用和更新您编辑的代码版本之后,我的结果还是一样。我更新了您的代码,对其进行了一些修改,发现在第一行输出之后,openvpn 要求输入用户名,然后输入密码,然后它们就没有输入。我得到了正确的控制台输出,但结果不如预期。这是代码:

        public bool StartOpenVPN()
    {
        bool installed = false;
        int lineNo = 0;
        try
        {
            Console.WriteLine("Command = " + command + "\nOpening cmd");

            initProcess();
            process.Start();

            sw = process.StandardInput;
            Console.WriteLine("Has Exited after SW = " + process.HasExited.ToString());
            //sw.WriteLine("123b5df33f");
            //sw.WriteLine("*3FgYxyt");
            //Console.WriteLine("Has Exited after writing data = " + process.HasExited.ToString());

             while (process.HasExited == false)
             {
                 string d = process.StandardOutput.ReadLine();
                 Console.WriteLine("Line = " + d);
                 lineNo++;
                 if (lineNo == 1)
                 {
                     Console.WriteLine("Writing Details");
                     sw.WriteLine("foo");
                     sw.Flush();
                     Console.WriteLine("Wrote Username");
                     sw.WriteLine("*baa");
                     sw.Flush();
                     Console.WriteLine("Wrote Password");
                 }
             }

             process.Close();
             process = null;
            Console.WriteLine("Finished cmd");
        }
        catch (Exception e)
        {
            Console.WriteLine("Errror Installing Tap Adapter : " + e.Message);
            Console.WriteLine(e.StackTrace);
        }

        return installed;
    }

输出是:

Command = files\openvpn --config files\client.ovpn

打开cmd 在 SW = False 后退出 线路 = Fri Mar 11 18:10:06 2011 OpenVPN 2.1.1 i686-pc-mingw32 [SSL] [LZO2] [PKCS11] 建于 2010 年 2 月 17 日 写作细节//在第一行之后,它正在尝试写作 写用户名 写密码 Line = Fri Mar 11 18:10:06 2011 错误:无法从标准输入读取 Auth 用户名 线路 = 2011 年 3 月 11 日星期五 18:10:06 退出 线 = 完成cmd

无法确定应用程序是否无法正确地将输入输入到标准输入或 openvpn 无法接受它。我还尝试了 sw.WriteLine("foo" + ConsoleKey.Enter);,也产生了相同的结果。在执行/调试时想知道并尝试查看 cmd 窗口以了解确切结果,但也看不到。

如果我们通过命令提示符正常运行openvpn,我们得到的是:

D:\>files\\openvpn --config files\\client.ovpn

2011 年 3 月 11 日星期五 18:03:48 OpenVPN 2.1.1 i686-pc-mingw32 [SSL] [LZO2] [PKCS11] bui 2010 年 2 月 17 日 输入验证用户名:

对此感到困惑,真的。

【问题讨论】:

    标签: c# process input cmd


    【解决方案1】:

    您实际上在 finally 块中关闭了您的进程。尝试在Console.WriteLine("Finished cmd"); 之前添加process.WaitForExit();

    或者,您可以将process.BeginOutputReadLine(); 替换为:

    while (!process.HasExited)
    {
        string d = process.StandardOutput.ReadLine();
        Console.WriteLine("Line = {0}", d);
    }
    

    更好的方法是将 make process 放入成员变量而不是局部变量。只需将finally 块中的代码移动到进程退出处理程序:

    void process_Exited(object sender, EventArgs e)
    {
        // Code from finally here
    }
    

    但你必须记得添加退出的处理程序:

    process.Exited += new EventHandler(process_Exited);
    

    另一方面,关闭输入流可能会导致一些问题。尝试删除以下 2 行,看看会发生什么

    sw.Flush();
    sw.Close();
    

    以下是您的代码的编辑版本:

    private void initProcess()
    {
        processInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
        processInfo.UseShellExecute = false;
        processInfo.RedirectStandardInput = true;
        processInfo.RedirectStandardOutput = true;
        processInfo.WindowStyle = ProcessWindowStyle.Normal;
    
        process = new Process();
        process.StartInfo = processInfo;
        //process.Exited += new EventHandler(process_Exited); // Actually no longer required, since HasExited will test for it
        // return; // return not required
    }
    
    // No longer need Exited, since HasExited checks for it
    /*
    void process_Exited(object sender, EventArgs e)
    {
        Console.WriteLine("Into process_Exited....");
        processInfo = null;
        if (process != null)
        {
            sw = null;
            // Do not close here. Closing here will prevent "process.WaitForExit()" and "process.HasExited" from working
            //process.Close();
            //process = null;
        }
    }
    */
    
    public bool StartOpenVPN()
    {
        bool installed = false;
        try
        {
            Console.WriteLine("Command = " + command);
    
            Console.WriteLine("Opening cmd");
    
            initProcess();
            process.Start();
    
            sw = process.StandardInput;
            Console.WriteLine("Has Exited after SW = " + process.HasExited.ToString()); // RETURS FALSE BUT GOES TO process_Exited & for next line results is NullPointerException
            sw.WriteLine("foo");
            sw.WriteLine("*baa");
             //sw.Flush();
            //sw.Close();
    
            //process.BeginOutputReadLine();
            //process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
             while (process.HasExited == false)
             {
                 string d = process.StandardOutput.ReadLine();
                 Console.WriteLine("Line = " + d);
             }
    
            // process.WaitForExit(); // Not required, since HasExited already check whether process has exited
            // Added here from Exited, so that it only close after exit
            process.Close();
            process = null;
            Console.WriteLine("Finished cmd");
        }
        catch (Exception e)
        {
            Console.WriteLine("Errror Opening : " + e.Message);
            Console.WriteLine(e.StackTrace);
        }
    
        return installed;
    }
    

    【讨论】:

    • 嗨,Fun Mun Pieng,我实现了你的方式。现在在正常执行时,我只看到第一行输出,即 OpenVPN 2.1.1 i686-pc-mingw32 [SSL] [LZO2] [PKCS11],建于 2010 年 2 月 17 日,系统挂起 - 我想等待进程退出。如果我在调试模式下运行,我只会看到“Opening cmd”和“Finished cmd”;没有可见的输出代码。我还添加了 ("Into process_Exited....");在 process_Exited 中,但根本看不到那条线。顺便说一句,在第一行之后,第二行是“输入用户名”;是等待输入的应用程序,我们不知道。他们是否知道该过程是否正在等待?
    • @user455979,我已经用更多信息更新了答案......你应该注意我的一些示例代码是替代品。您可以使用其中一种,但不能同时使用它们。
    • Mun,使用您编辑的代码,我还更新了我的代码并显示了结果,两者都添加到了问题中。
    【解决方案2】:

    不要尝试通过命令行传递用户名和密码,而是使用 OpenVPN 的 --auth-user-pass [file] 开关,其中 [file] 是所有两行:

    用户 密码

    我从未尝试过,但它是文档所说的。

    所以你的开场白是这样的:

    string command = "files\\openvpn --config files\\client.ovpn --auth-user-pass files\\TEMP-AUTH";
    

    请记住在完成后立即删除 TEMP-AUTH。

    【讨论】:

    • 这就是我目前使用 openvpn 2.1.1 的方式。在运行时创建一个文件,连接到 openvpn 并销毁该文件。但坚持使用最新版本,即 2.1.4 的 openvpn。从 2.1.3 开始,不再支持 --auth-user-pass。我的下一个选择是使用管理,但服务员拒绝了。不接受参数。所以现在剩下的唯一选择是通过标准输入传递用户名和密码。因此必须解决这个问题。
    【解决方案3】:

    这个查询对我来说是无法解决的,因为 openvpn 不支持从应用程序接受标准输入。

    感谢大家的帮助、想法和建议。

    谢谢。

    【讨论】:

    • 该死,我正在尝试为另一个应用程序制作类似的东西,两天无所事事后,也得出了这样的结论。
    猜你喜欢
    • 2017-05-25
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    相关资源
    最近更新 更多