为什么没有显示应用程序的输出
本文关键字:输出 应用程序 显示 为什么 | 更新日期: 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所指出的,您是否尝试过将应用程序的输出类型设置为"控制台应用程序"?