C#:是否可以根据开关将单个应用程序作为控制台或 Windows 应用程序运行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1786840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 13:29:15  来源:igfitidea点击:

C#: Is it possible to have a single application behave as Console or Windows application depending on switches?

c#console-applicationwindows

提问by Svish

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?

有什么办法可以做到这一点,还是我必须创建两个单独的项目,一个控制台应用程序和一个 Windows 应用程序?

回答by adrianbanks

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

虽然与您所问的不完全相同,但我过去通过使用FreeConsolepInvoke 删除控制台窗口来实现此行为的外观

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

您将项目的输出类型设置为控制台应用程序。然后将外部调用定义为FreeConsole

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

Then, in you Mainmethod you switch based on your conditions. If you want a UI, call FreeConsolebefore opening the form to clear the console window.

然后,在您的Main方法中,您可以根据自己的条件进行切换。如果您需要 UI,请FreeConsole在打开表单之前调用以清除控制台窗口。

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 hackthough and has a bad smell, so I'd seriously consider whether you do want to go down this route.

不过,这有点小技巧,而且气味难闻,所以我会认真考虑您是否确实想走这条路。

回答by Aaron

From 'The Old New Thing'

出自《旧的新事物》

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

如何编写可以作为控制台或 GUI 应用程序运行的程序?

You can't.

你不能。

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

(我会让你点击文章了解如何伪造它的详细信息)

回答by Charles Bretana

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

当然,只需根据命令行中传递的参数,在静态 main(string[] args) 中放置一个 switch 语句(或 if else 构造)。我也这样做是为了在作为服务或作为控制台执行之间切换......

NOTE: Set project type as Console App

注意:将项目类型设置为 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...

编辑:感谢 Adrian Bank 的回答,FreeConsole() 是“分配”控制台窗口的更好方法,而不仅仅是最小化它......

回答by Ed S.

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.

它们是两种不同的范式,我认为使用这样的命令行开关不是一个好主意。为什么不将核心逻辑构建到控制台应用程序中,然后在需要时从 GUI 调用它呢?这将很好地将 UI 与实现分开,但仍会提供一种在需要时独立使用控制台应用程序的方法。

回答by Darryl Braaten

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

可执行文件被标记为窗口应用程序或控制台应用程序。您可以在 Visual Studio 中项目的属性中看到这一点,在应用程序、输出类型下

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.

您可以通过使用两个应用程序来模拟行为,一个控制台应用程序如果不带参数执行,则会启动 GUI 应用程序。您可能会看到控制台窗口闪烁,除非您从已经打开的控制台运行。

回答by dkackman

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.

如果不实现您自己的控制台窗口版本,答案是否定的。当 Windows 加载您的可执行文件时,它会根据 PE 标头中的数据决定是否为您提供控制台窗口。因此,您可以使窗口化应用程序没有窗口,但不能使窗口化应用程序具有控制台。

回答by ecreif

You can, but with some drawbacks:

你可以,但有一些缺点:

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

如果您为子系统 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

但是随后您必须通过 AttachConsole(-1) http://msdn.microsoft.com/en-us/library/windows/desktop/ms681952%28v=vs手动将进程附加到调用控制台 (cmd.exe) 。 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:

仅此一项并不能完成工作。您还必须通过这些调用将三个 std 流重定向到控制台:

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

样本来自: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.exeThis way you also get the return value of your app and you can check it with %errorlevel% as usual.

您的 WinMain 调用的问题在于 Windows 已经分叉了您的进程,因此调用 cmd.exe 控制台已经从您的 .exe 返回并继续执行下一个命令。为了防止这种情况,您可以使用start /wait myexe.exe这种方式调用您的 exe,您还可以获得应用程序的返回值,您可以像往常一样使用 %errorlevel% 进行检查。

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

如果有办法防止该进程与子系统窗口分叉,请告诉我。

Hope this helps.

希望这可以帮助。