C#: Is it possible to have a single application be

2019-01-18 05:45发布

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?

7条回答
beautiful°
2楼-- · 2019-01-18 06:22

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)

查看更多
做自己的国王
3楼-- · 2019-01-18 06:23

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...

查看更多
家丑人穷心不美
4楼-- · 2019-01-18 06:23

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.

查看更多
我命由我不由天
5楼-- · 2019-01-18 06:34

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.

查看更多
对你真心纯属浪费
6楼-- · 2019-01-18 06:37

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.

查看更多
Viruses.
7楼-- · 2019-01-18 06:37

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.

查看更多
登录 后发表回答