从C#应用程序创建一个命令行窗口并写入它

4
我正在为Rhino的Grasshopper开发一个C#组件。由于我正在运行一些相当重的迭代分析,所以我想不断将结果输出到cmd窗口,只是为了确保分析实际上正在运行。 这是我尝试过的方法:
using System.Diagnostics;


Result results = new Result();
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = false;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();

do {
    results = RunHeavyOperation(results);
    cmd.StandardInput.WriteLine("echo " + results.usefulInfo);
} while (!results.conditionForEnd);

cmd.WaitForExit();

Result RunHeavyOperation(Result previousResults) {
    Result res = doHeavyStuff(previousResults);
    return res;
}
我意识到我缺少一部分,但是它是什么?

记录一下,我暂时使用了 System.Diagnostics.Debug.Write(results.usefulInformation); 解决了这个问题,但如果应用程序进入生产环境,这种方法就不可行了。 - Toivo Säwén
https://dev59.com/xXA65IYBdhLWcg3wzyL8 - bh_earth0
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
10
你的方法不正确:你目前没有写入控制台窗口。相反,你通过启动 cmd.exe 并将内容写入该进程的标准输入管道来创建了一个进程。但是 cmd.exe 并不知道这一点。这与通过键盘在控制台中输入是不同的,甚至可能会产生奇怪的效果。
想象一下,如果你输出了一个换行符,那么 cmd.exe 可能会尝试以前输出的内容作为命令来“执行”。 正确的方法是调用 AllocConsole。通过此调用,你可以为你的进程创建一个控制台窗口,并且可以简单地使用 Console.WriteLine() 输出。 完成工作和记录后,你最终需要通过 FreeConsole 关闭和释放此控制台。 因此,导入这两个本机方法:
internal sealed class NativeMethods
{
    [DllImport("kernel32.dll")]
    public static extern bool AllocConsole();

    [DllImport("kernel32.dll")]
    public static extern bool FreeConsole();
}

并在您的代码中使用它们:

NativeMethods.AllocConsole();

// start work
Console.WriteLine("log messages...");

// finished work

NativeMethods.FreeConsole();
请注意,FreeConsole()函数会关闭控制台窗口,因此所有您的日志消息都将丢失。而且,控制台仅有一个很大的缓冲区,如果信息离开了缓冲区,就无法回滚到早期的消息。 因此,将日志消息写入文件以便稍后分析可能是更好的选择。

是的,这就是我要找的。谢谢! - Toivo Säwén
1
我能在WinForms应用程序中做到这一点吗?我可以打开控制台,但是什么也没有写入! - Olivier Jacot-Descombes
@OlivierJacot-Descombes,是的,你可以这样做,我刚刚重新测试了一下,对我有效。 - René Vogt
我不得不使用这个答案中的代码才能使它工作。但是,当从VS 2017内部启动应用程序时,输出仍然被重定向到调试输出窗口。只有在从VS外部启动应用程序时才有效。 - Olivier Jacot-Descombes
@OlivierJacot-Descombes,我在VS2017中测试通过。你是在调试器附加的情况下启动的吗?那当然不会工作,因为已经有一种控制台附加了(调试器)。由于OP希望它在生产中工作,所以我认为我的代码没问题。如果你不使用调试启动,它就能正常工作。 - René Vogt
显示剩余2条评论

0
在Visual Studio中创建控制台应用程序。在VS 2017中,它看起来像这样(在启动页面上):

enter image description here

控制台应用程序会自动打开命令控制台。然后,您可以在其中编写代码。

Console.WriteLine("hello");
当程序终止时,控制台会自动关闭。因此,如果您想保持其打开状态,请确保在结尾处调用Console.ReadKey();

这很好,但是应用程序已经深入开发了 - 将现有应用程序迁移到控制台应用程序是否容易? - Toivo Säwén
1
这取决于您是否已经创建了WinForms或WPF应用程序并已经创建了UI,或者您只编写了业务逻辑。在后一种情况下,您将不需要进行任何转换。当然,一个应用程序不能同时是控制台和WinForms或WPF应用程序。 - Olivier Jacot-Descombes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,