创建一个 cmd window 并从 C# 应用程序写入它

Create a cmd window and write to it from C# application

我正在为 Grasshopper for Rhino 开发 C# 组件。因为我是 运行 一些相当繁重的迭代分析,所以我想将结果连续输出到 cmd window 只是为了确保分析实际上是 运行.

这是我尝试过的:

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;
}

我意识到我遗漏了一部分,但那是什么?

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

控制台应用程序会自动打开命令控制台。然后你可以用

写信给它
Console.WriteLine("hello");

程序终止时控制台自动关闭。因此,如果您想保持打开状态,请务必在最后调用 Console.ReadKey();

您的方法是错误的:您目前没有写入控制台 window。相反,您通过启动 cmd.exe 并写入到该进程 的 标准输入管道来创建一个进程。 cmd.exe 不知道。这与通过键盘在控制台中键入不同,甚至会产生奇怪的效果。
假设你输出一个换行符,所以 cmd.exe 可能会尝试 "execute" 你之前输出的内容作为命令。

正确的方法是调用AllocConsole。通过这个调用,您可以为您的进程创建一个控制台 window,并通过 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() 关闭 控制台 window,因此您的所有日志消息都会丢失。控制台只有这么大的缓冲区,如果离开缓冲区,您将无法回滚到旧消息。

因此,将您的日志消息简单地写入一个您可以稍后分析的文件中可能是一个更好的主意。