为什么没有显示应用程序的输出

本文关键字:输出 应用程序 显示 为什么 | 更新日期: 2023-09-27 18:21:07

>我有一个应用程序,具有以下Main

static void Main(string[] args)
{
     Console.WriteLine("started");
     if (args.Length == 0)
     {
          Application.EnableVisualStyles();
          Application.SetCompatibleTextRenderingDefault(false);
          Application.Run(new Form1());
     }
     else
     {
          File.WriteAllText("./file.txt", "hello");
     }
}

我希望它支持从命令行运行,在某些脚本中使用,以及像 GUI 应用程序一样运行。但是,如果我从命令行运行它并向其传递一个参数,我可以看到文件已创建,但我看不到 Console.WriteLine 生成的任何输出。为什么?

为什么没有显示应用程序的输出

我想

我发现了问题,如果我错了,请原谅我。
创建 GUI 应用程序并从控制台窗口运行它时,其标准输出流不会发送到以前打开的控制台窗口,因此不会显示。
但是如果你尝试运行yourexe.exe > test.txt你可以看到你写的所有内容Console.WriteLine

在以下情况下它不起作用:

这是因为启动 WinForms 的控制台窗口 应用程序属于 cmd.exe 进程,它独立于 您的WinForms申请流程。

我在本文中发现了这一点,它还提供了一些使用AttachConsole Win32方法的解决方法

您似乎想在控制台模式和 GUI 模式下运行应用程序。 这个例子就是这样做的。 基本上,您创建一个表单应用程序,并在 Main 中有条件地调用AllocConsole如果从资源管理器运行。如果从命令提示符运行,则必须通过查看父进程来检测,则可以使用 AttachConsole 附加到其控制台。 在这里,我已经对值进行了硬编码,但您可以查看参数并决定执行任何操作。

基本上这个应用程序有三种模式

  • 从命令提示符启动将使用父控制台bParentConsoleMode
  • bUsingOwnConsole如果在资源管理器中双击,则必须创建一个新的控制台
  • 最后,当上述情况都不正确时,它将作为常规表单应用程序运行。

    static class Program
    {
        [DllImport("kernel32.dll")]
        static extern bool AttachConsole(int dwProcessId);
        private const int ATTACH_PARENT_PROCESS = -1;
    
        [DllImport("kernel32.dll")]
        private static extern bool AllocConsole(); 
         [STAThread]
        static void Main()
        {
            bool bParentConsoleMode = true;
            bool bUsingOwnConsole = true;
            if (bParentConsoleMode)
            {
               AttachConsole(ATTACH_PARENT_PROCESS);
                Console.WriteLine("Using parent console");
                Console.ReadLine();
            }
            else if (bUsingOwnConsole)
            {
                AllocConsole();
                Console.WriteLine("Using own console");
                Console.ReadLine();
            }
            else //gui mode
            {
                Console.WriteLine("This is cool");
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }
    

请参阅Raymond Chen的这篇文章:如何编写可以作为控制台或GUI应用程序运行的程序?

摘录:

你不能,但你可以试着伪造它。

[...]

有些人想编写我称之为"机会主义"的控制台程序。这些程序将使用其父级的控制台(如果可用(,但如果不可用,则不希望为它们创建控制台。内核不支持这种类型的程序,但这并没有阻止一些人提出聪明的解决方法。

问题在于,"附加到现有控制台窗口进行输入和输出,还是作为无控制台的 GUI 应用运行?"的决定发生在该过程实际开始之前。不能编写基于命令行参数做出该决定的代码。

Windows 强制您在编译时做出决定:此应用是否将使用控制台(在这种情况下,它始终具有控制台窗口,如果它是从图标或"开始"菜单启动的,则会打开一个新窗口(,还是不使用控制台(在这种情况下,它无法将输入或输出定向到启动它的控制台窗口 - 它可以, 但是,请创建一个新的控制台窗口(。如果要始终拥有控制台,请将构建类型更改为"控制台应用程序";如果您不想永远没有控制台,请将其保留为"Windows 应用程序"。

在Raymond的帖子中引用的聪明的解决方法,在链接腐烂的情况下,是devenv(Visual Studio(和ildasm:

在VisualStudio案例中,实际上有两个二进制文件:devenv.com 和devenv.exe.Devenv.com 是一个控制台应用程序.exe。键入 devenv 时,由于 Win32 探测规则,将执行 devenv.com。如果没有输入,devenv.com 将启动 devenv.exe,然后退出自身。如果有输入,devenv.com 会像普通控制台应用一样处理它们。

在ildasm

的情况下,只有一个二进制:ildasm.exe。它首先编译为 GUI 应用程序。后来的 editbin.exe 用于将其标记为控制台子系统。在其主要方法中,它确定是否需要作为控制台模式或 GUI 模式运行。如果需要以 GUI 模式运行,它会以 GUI 应用程序的形式重新启动自身。

我使用以下代码来执行类似操作:

 Console.WriteLine("started");
 if (args.Length == 0)
 {
     ProcessForConsole(argsParser);
 }
 else
 {
     NativeMethods.FreeConsole();
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);
     Application.Run(new Form1());                
 }    

....

 [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int FreeConsole();

将主应用程序设置为控制台应用程序,然后您 FreeConsole 将其分离。

进程可以使用 FreeConsole 函数将自身与其控制台分离。如果其他进程共享控制台,则控制台不会被销毁,但调用 FreeConsole 的进程无法引用它。当附加到控制台的最后一个进程终止或调用 FreeConsole 时,控制台将关闭。

来自微软。

正如Marco所指出的,您是否尝试过将应用程序的输出类型设置为"控制台应用程序"?

相关文章: