Ben Rinaca

I know there are possible solutions out there, but none that fit my exactly what I'm trying to do. Let me explain my situation and why the existing solutions aren't favorable:

I am writing an administrative tool that is primarily a Windows Forms interface, but allows a user to run it through command line arguments for batch processing, automation, etc. When the application is launched through Explorer (by Start Menu icon or double clicked from its folder) it should immediately run the GUI with no console output. If it is run from a command line with no arguments, it should attach to the console, output the usage, run the GUI, and write status/debug info to the console as needed. If it is run by command line with arguments, it sould attach to the console, process the arugments, and write status/debug info to the console as needed.

I have all of these scenarios working except for the time at which the console is attached to. I can't seem to make it attach at a time that offers a smooth, professional user experience. Here are the solutions I've come across, along with an explanation as to why I don't see it fit:

* Set the output type to Console Application in the project's properties - this causes a console window to appear throughout the life of the application no matter which way the application was launched (from Start Menu, icon double click, command line, etc).

* Set the output type to Console Application in the project's properties and call kernel32.dll's FreeConsole() if not passed command line arguments - this causes the console window to flicker briefly on screen before launching the GUI from Start Menu or icon double click, but more importantly does not write status/debug info to the console in the event that the app was launched from a console.

* Set the output type to Windows Application in the project's properties and call kernel32.dll's AllocConsole() - has the opposite negative effect of the above FreeConsole() solution, but more importantly allocates a new console even if the app was originally run from the console.

* Set the output type to Windows Application in the project's properties and call kernel32.dll's AttachConsole(-1) - this solution will attach the current console to the appliaction in the event that there is a console to attach to. This is the most fitting solution, however there is one problem that makes it unfit. When run from the command line, the console is not attached until after the Program.Main is invoked. Even if AttachConsole(-1) is the first statement in Program.Main, the console is still released back to the command line before execution of the program takes place. This means that the command prompt returns to the working directory immediately upon running the app, before the output begins. This leaves the console open to do other things/run other apps. Most importantly, it does not return to the command prompt on app termination (because it returns immediately on invoke), leaving the exit experience feeling as though the process is still running.

My question is this - is there any way to dynamically acheive the "Output Type = Console Application" feel when an app is run from the command line but still offer the "Output Type = Windows Application" if it is not run from the command line

Thanks in advance for your help. Please feel free to ask any questions if my explanation is foggy.



Re: Windows Forms General Console and GUI app in one

nobugz

Try this:

static class Program {
[STAThread]
static void Main() {
if (AttachConsole(-1)) {
Console.WriteLine("Running in console mode. Press ENTER to terminate app");
Console.ReadLine();
}
else {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AttachConsole(int procid);
}






Re: Windows Forms General Console and GUI app in one

Ben Rinaca

That still doesn't do it for me. The AttachConsole(-1) is returning true, but the console is not truely "attached" as if the app was a console app.

Example 1 - Immediately after you run the app from the command line, you still see the command prompt return before program execution. Pressing enter at the end of execution sends an empty command, returning back to the command prompt again and appearing to be the same as if it was a console app. Actually, on the next press of the enter key is when you're Console.ReadLine() will be processed. I noticed this by putting a Console.WriteLine("exiting"); following the Console.ReadLine();. After program execution the first press of the enter key gives me the command prompt again. The second press of the enter key gives me the expected "exiting" on the command line.

Example 2 - Replace Console.ReadLine(); with Console.ReadKey(true);. This statement is meant to intercept a keypress to the console and handle it so that it does not appear in the console. This is how I handle the shutdown of my console app. Without the app specifically set as Output Type = Console Application I cannot do this because 1) you must press enter before the Console.ReadKey(true) gets processed (as explained in example 1) and 2) the keypress is never intercepted - no matter what I do, it will still output that keypress to the console.

Thanks for your response.





Re: Windows Forms General Console and GUI app in one

Ben Rinaca

I suppose I could settle for the second solution, Set the output type to Console Application in the project's properties and call kernel32.dll's FreeConsole(), and just have no way to get around the console flicker if there is a way for the application to know whether or not is was launched from a console.

I will only want to call FreeConsole() if the app wasn't launched from a console so that status/debug info can be printed, even if no arguments are given and the GUI is launched. The only way FreeConsole() should be called is if the app was launched by Start Menu or double-click.





Re: Windows Forms General Console and GUI app in one

nobugz

This is all normal when you share the console between apps, their output will get intermingled. You'll have to block cmd.exe by starting your program with the "start" command.





Re: Windows Forms General Console and GUI app in one

Ben Rinaca

Even start does not allow me to use Console.ReadKey(true) without first pressing enter once the app execution has begun.

Looks like I'm stuck with just having a console window open with my app no matter what... I thought for sure there had to be a simple answer somewhere.





Re: Windows Forms General Console and GUI app in one

nobugz

AttachConsole(-1) returns True if the app was started from a console. Call FreeConsole(), then AllocConsole().





Re: Windows Forms General Console and GUI app in one

Shane Scribner

Why do you have to press the Enter key once the Console Application has terminated





Re: Windows Forms General Console and GUI app in one

Markus Essl

I have the same problem, but did not find a good solution to that point yet. BUT, I found following things:

http://msdn.microsoft.com/msdnmag/issues/04/02/CQA/
That article basically say, you should create an exe with and extension of .com (which is an exe file as well, just renamed). Calling it from the command line will search for a file with the extension .com first, and therefor this can be made working. (look at pathext environment variable).

"start" command works in your case as well (it works fine with me), but you have to specify the parameter "/w". If not, both programs (cmd.exe and my.exe) access the same console at the same time, so you can typ in dir - and if cmd.exe is fast enough to catch it, it will display the directory, as well as the output of my program. "start /w" does the trick.

Still, it is not a good solution for me - i want to have one EXE file, not two. And I have no AttachConsole, because i have to support Windows2000 Server as well. That article mentioned that it is possible to do that, but too complicated. I'd go for a complicated solution as well, if someone told me how. Also, I still have to support Windows 2000 (Server), so AttachConsole does not work - and i can not live with the FreeConsole flicker. I'm using C++, not C#, so maybe there are more solutions for me available.

Does anyone know a link to a solution Any Hints
Maybe there is a third /subsystem (where the two would be console and windows) Maybe there is one bit that tells the cmd.exe to wait for the process to finish, and one to allocate a console