我有一个应用程序,它具有以下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
产生的任何输出。那是为什么?
答案 0 :(得分:3)
我想我发现了问题,如果我错了,请原谅我
当您创建GUI应用程序并从控制台窗口运行它时,其标准输出流不会发送到先前打开的控制台窗口,因此它不会显示。
但是,如果您尝试运行yourexe.exe > test.txt
,则可以看到您使用Console.WriteLine
答案 1 :(得分:2)
它不会起作用因为:
那是因为启动WinForms的控制台窗口 应用程序属于cmd.exe进程,它独立于 你的WinForms申请流程。
我在this article中找到了这个,这也为AttachConsole Win32 method提供了一些解决方法
答案 2 :(得分:2)
您似乎希望在控制台模式和GUI模式下运行应用程序。这个例子做到了。基本上,您创建一个Form应用程序,如果从资源管理器运行,则在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());
}
}
}
答案 3 :(得分:1)
请参阅Raymond Chen的这篇文章:How do I write a program that can be run either as a console or a GUI application?
摘录:
你不能,但你可以试着伪造它。
[...]
有些人想写我称之为“机会主义”的控制台程序。这些程序将使用其父级控制台(如果可用),但如果不是,则不希望为其创建控制台。内核不支持这种类型的程序,但这并没有阻止某些人提出clever workarounds。
问题在于“决定”附加到现有控制台窗口以进行输入和输出,还是作为无控制台GUI应用程序运行?“在流程实际开始之前发生。您无法编写基于命令行参数做出决定的代码。
Windows迫使您在编译时做出决定:这个应用程序是否会使用控制台(在这种情况下,总是有一个控制台窗口,如果它被启动则会打开一个新的控制台窗口从一个图标或开始菜单),或者它不会使用控制台(在这种情况下它不能直接输入或输出它从它启动的控制台窗口 - 但它可以, create a new console window)。如果您想要始终拥有控制台,请将您的构建类型更改为“控制台应用程序”;如果你想永远不要有控制台,请把它留作“Windows应用程序”。
雷蒙德的文章中提到的聪明的解决方法,如果链接腐烂,是devenv(Visual Studio)和ildasm:
在VisualStudio案例中,实际上有两个二进制文件:devenv.com和devenv.exe。 Devenv.com是一款控制台应用。 Devenv.exe是一个GUI应用程序。当您键入devenv时,由于Win32探测规则,会执行devenv.com。如果没有输入,devenv.com将启动devenv.exe,并退出。如果有输入,devenv.com会将它们作为普通的控制台应用程序处理。
在ildasm案例中,只有一个二进制文件:ildasm.exe。它首先被编译为GUI应用程序。稍后editbin.exe用于将其标记为控制台子系统。在其主要方法中,它确定是否需要以控制台模式或GUI模式运行。如果需要以GUI模式运行,它会将自身重新启动为GUI应用程序。
答案 4 :(得分:0)
正如Marco指出的那样,您是否尝试将应用程序的输出类型设置为“控制台应用程序”?
答案 5 :(得分:0)
我使用以下代码执行类似的操作:
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时,控制台将关闭。