Reputation: 96797
I have an application, that has the following 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");
}
}
I want it to support running from command line, to be used in some scripts, as well as running like a GUI app. However, if I run it from the command line, and pass it a parameter, I can see that the file gets created, but I don't see any of the output produced by Console.WriteLine
. Why is that?
Upvotes: 4
Views: 172
Reputation: 24403
It seems like you want to run a application in both console mode and in GUI mode. This example does it. Bascically you create a Form application and in the Main conditionally call AllocConsole
if run from explorer. If run from a command prompt which you will have to detect by looking at the parent process you can attach to its console using AttachConsole
. Here I have hardcoded the values but you can look at the arguments and decide to do anything.
Basically this app has three modes
bParentConsoleMode
that will use the parent console if launched from command promptbUsingOwnConsole
if double clicked in explorer you will have to create a new consoleLastly when neither of the above is true it runs as a regular form application.
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());
}
}
}
Upvotes: 2
Reputation: 878
I used the following code to do something similar:
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();
Set the main application to be a console app and then you FreeConsole to detach it.
A process can use the FreeConsole function to detach itself from its console. If other processes share the console, the console is not destroyed, but the process that called FreeConsole cannot refer to it. A console is closed when the last process attached to it terminates or calls FreeConsole.
From microsoft.
Upvotes: 1
Reputation: 97696
See this post by Raymond Chen: How do I write a program that can be run either as a console or a GUI application?
Excerpt:
You can't, but you can try to fake it.
[...]
There are some people who want to write what I call an "opportunistic" console program. These are programs that will use the console of their parent if available, but do not want a console created for them if not. The kernel doesn't support this type of program, but that hasn't stopped some people from coming up with clever workarounds.
The problem is that the decision of "attach to the existing console window for input and output, or run as a console-less GUI app?" happens before the process actually starts. You can't write code that makes that decision based on command-line parameters.
Windows forces you to make the decision at compile-time: is this app going to use a console (in which case it always has a console window, and opens a new one if it was launched from an icon or the Start menu), or is it not going to use a console (in which case it cannot direct input or output to the console window it was launched from -- it can, however, create a new console window). If you want to always have a console, change your build type to "Console Application"; if you want to never have a console, leave it as "Windows Application".
The clever workarounds cited in Raymond's post, in case of link rot, are devenv (Visual Studio) and ildasm:
In VisualStudio case, there are actually two binaries: devenv.com and devenv.exe. Devenv.com is a Console app. Devenv.exe is a GUI app. When you type devenv, because of the Win32 probing rule, devenv.com is executed. If there is no input, devenv.com launches devenv.exe, and exits itself. If there are inputs, devenv.com handles them as normal Console app.
In ildasm case, there is only one binary: ildasm.exe. It is first compiled as a GUI application. Later editbin.exe is used to mark it as console subsystem. In its main method it determines if it needs to be run as console mode or GUI mode. If need to run as GUI mode, it relaunches itself as a GUI app.
Upvotes: 1
Reputation: 57573
I think I've found problem, please forgive me if I'm wrong.
When you create a GUI application and run it from a console window, its standard output stream is not sent to previously opened console window, so it's not shown.
But if you try to run yourexe.exe > test.txt
you can see everything you wrote with Console.WriteLine
Upvotes: 3
Reputation: 139758
It won't work becase:
That’s because the console window that launched your WinForms application belongs to the cmd.exe process, which is separate from your WinForms application process.
I found this in this article which is also offers some workaround with the AttachConsole Win32 method
Upvotes: 2
Reputation: 6136
As Marco has pointed out, Have you tried setting the output type of your application to "Console Application" ?
Upvotes: 0