8

I have a simple application that I would like to sort of automate via switches. But when I do run it via switches I don't really want a user interface showing. I just want it to run, do it's job, print stuff out in the console, and exit. On the other hand if I don't run it with any switches I want the user interface to pop up. And in this case I don't really want a console window hanging around in the background.

Is there any way I can do this, or do I have to create two separate projects, one Console Application and one Windows Application?

Svish
  • 152,914
  • 173
  • 462
  • 620
  • 1
    have you tried just inserting your code in the Main() function that's generated when you create a winforms app? Instead of calling Application.Run()? – No Refunds No Returns Nov 23 '09 at 23:45
  • Somewhat related, especially if you want to write to the Console from a Windows application: http://stackoverflow.com/questions/666823/writing-to-the-command-line-in-a-windowed-app – Dirk Vollmar Nov 24 '09 at 00:12

7 Answers7

11

Whilst not exactly what you have asked, I've achieved the appearance of this behaviour in the past by using the FreeConsole pInvoke to remove the console window.

You set the output type of the project to be a console application. You then define the extern call to FreeConsole:

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

Then, in you Main method you switch based on your conditions. If you want a UI, call FreeConsole before opening the form to clear the console window.

if (asWinForms)
{
    FreeConsole();       
    Application.Run(new MainForm());
}
else
{
    // console logic here 
}

A console window does briefly appear at startup, but in my case it was acceptable.

This is a bit of a hack though and has a bad smell, so I'd seriously consider whether you do want to go down this route.

adrianbanks
  • 81,306
  • 22
  • 176
  • 206
  • This is a very good approach for this situation. You can also AllocConsole (my deleted post showed this), but then your console is detached from the calling shell, if called from a shell. – Reed Copsey Nov 24 '09 at 00:24
  • Won't run well under Mono anymore then though, will it? – Svish Nov 24 '09 at 15:01
  • This will not work in all cases, because the executable will have the same PE header which tells the system if it is console or not. See http://stackoverflow.com/questions/7613880/difference-between-console-and-winforms-applications-when-running-from-cmd – Tomas Kubes Apr 18 '15 at 14:43
8

From 'The Old New Thing'

How do I write a program that can be run either as a console or a GUI application?

You can't.

(I'll let you click on the article for the details of how to fake it)

Aaron
  • 9,123
  • 5
  • 40
  • 38
6

Sure, just put a switch statement (or if else construction) in the static main(string[] args), based on arguments passed in command line. I also do this to switch between executing as a service or as a console...

NOTE: Set project type as Console App

[DllImport("kernel32.dll", SetLastError=true)]
private static extern int FreeConsole();    
[STAThread]
static void Main(string[] args)
        {
            if (args.Length == 0 && args[0] == "C") // Console
            {                    
                // Run as console code  
                Console.WriteLine("Running as Console App");
                Console.WriteLine("Hit any Key to exit");
                Console.ReadLine();
          }
            else
            {
                //Console.SetWindowSize(1,1);
                //string procName = Assembly.GetExecutingAssembly().FullName;
                //ProcessStartInfo info = new ProcessStartInfo(procName );
                //info.WindowStyle = ProcessWindowStyle.Minimized;

                // EDIT: Thanks to Adrian Bank's answer - 
                // a better approach is to use FreeConsole()
                FreeConsole();
                Application.Run(new MyForm());
            }
        }

EDIT: Thanks to Adrian Bank's answer, FreeConsole() is much better approach to "dispense" with Console window than just minimizing it...

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • How do you propose to implement that exactly? – Ed S. Nov 23 '09 at 23:48
  • I think the "Run as Console" and "Run as winforms" are the interesting points here though. The OP could have guessed this much. – Ed S. Nov 23 '09 at 23:50
  • +1: I don't see why this would have been downvoted... it's fairly simple, and effective. If each UI type (forms vs console) is it's own assembly, then the switch/if will load the appropriate assembly and run it. – Steven Evers Nov 23 '09 at 23:50
  • System.Windows.Forms.dll will need to be referenced for this to work. – Zach Johnson Nov 23 '09 at 23:55
  • 2
    I guess people downvote it because it's not a real console app (those are impossible according to Raymond Chen: http://blogs.msdn.com/oldnewthing/archive/2009/01/01/9259142.aspx), but I think the approach is suitable for the OP's problem. I just think that the IF-Condition is completely wrong - should be an || I think. – Michael Stum Nov 24 '09 at 00:03
  • Still no implementation, Raymond Chen seems to think this is a bad idea, and still this is at the top. – Ed S. Nov 24 '09 at 00:04
  • 2
    If you do this from a windows app you will not have access to stdin and stdout to read or write things to the console. If you mark your exe as a console application you will have a console hanging around. – Darryl Braaten Nov 24 '09 at 00:06
  • Honestly... this does not tell the OP anything. – Ed S. Nov 24 '09 at 00:07
  • 1
    Indeed, this either runs the app with a GUI or hides it completely allowing no user input or output as expected from a console appliaction. – Joshua Nov 24 '09 at 00:11
  • Added more implementation, running as windows app causes console window to appear, so I added code to dispense with it. – Charles Bretana Nov 24 '09 at 02:08
  • @Charles Bretana: No, you added code to minimize the console window, not "dispense with it". What you really want is `FreeConsole` (as in adrianbanks's answer), but that has its own issues... – Daniel Pryden Nov 24 '09 at 02:13
  • @Daniel, I'm pretty sure I knew what my code did, but I appreciate your clarifying it for me {grin}... Actually, I meant "dispense" as in "remove" from the screen". But thanx I didn't know about 'FreeConsole' - that is a better approach... – Charles Bretana Nov 24 '09 at 02:22
2

They are two different paradigms, I don't think that using a command line switch like this is a good idea. Why not build the core logic into a console application and then call that from the GUI when needed? This would nicely separate the UI from the implementation but would still provide a way to use the Console app stand alone when needed.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • Although I agree with this, it is sometimes helpful to have a single application that works as console or GUI - Visual Studio is a common example of this... – Reed Copsey Nov 24 '09 at 00:21
  • Fair point, hadn't thought of that. I would assume that is a pretty rare thing to need though. – Ed S. Nov 24 '09 at 00:23
  • I'm thinking about making two UIs, one console and one graphical, but yeah. Best solution is to have them in one. This way you can use it as a regular app, and using in a script for example. – Svish Nov 24 '09 at 15:03
  • 1
    But you can still do that if you have two separate programs, I don't see the need for wrapping it all into one. – Ed S. Nov 24 '09 at 19:07
1

I believe the answer is no, or it was last time I looked into this problem.

The executable is marked as either a windowed application or a console application. You can see this in the properties for you project in Visual Studio, under application, Output type

You could simulate the behavior by having two application, a console application that if executed with no arguments launches the GUI application. You may see a console window flash, unless you ran in from an already open console.

Darryl Braaten
  • 5,229
  • 4
  • 36
  • 50
  • 1
    Visual Studio does that trick, there is a `devenv.exe` Windows application and a `devenv.com` console application. – Dirk Vollmar Nov 24 '09 at 00:09
0

You can, but with some drawbacks:

You can prevent having this black window on start up if you compile for subsystem Windows.

But then you have to attach the process to the calling console (cmd.exe) manually via AttachConsole(-1) http://msdn.microsoft.com/en-us/library/windows/desktop/ms681952%28v=vs.85%29.aspx

This alone does not do the job. You also have to redirect the three std streams to the console via these calls:

// redirect unbuffered STDOUT to the console
lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );

fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );

// redirect unbuffered STDERR to the console
lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf( stderr, NULL, _IONBF, 0 );

// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
// point to console as well
ios::sync_with_stdio();

Sample from: http://cygwin.com/ml/cygwin/2004-05/msg00215.html

The problem with your WinMain call is that windows already has forked out your process so the calling cmd.exe console will have returned from your .exe already and proceed with the next command. To prevent that you can call your exe with start /wait myexe.exe This way you also get the return value of your app and you can check it with %errorlevel% as usual.

If there is a way to prevent that process forking with subsystem windows please let me know.

Hope this helps.

ecreif
  • 1,182
  • 1
  • 12
  • 25
0

Without implementing your own version of a console window the answer is no. When Windows loads you executable it decides whether or not to give you a console window based on data in the PE header. So you can make a windowed app not have a window but you can't make a windoed app have a console.

dkackman
  • 15,179
  • 13
  • 69
  • 123