C#:根据交换机,是否可以将单个应用程序用作控制台或Windows应用程序?

时间:2009-11-23 23:40:57

标签: c# console-application windows

我有一个简单的应用程序,我希望通过交换机实现自动化。但是,当我通过开关运行它时,我真的不希望显示用户界面。我只是想让它运行,做它的工作,在控制台中打印出东西,然后退出。另一方面,如果我不使用任何开关运行它,我希望弹出用户界面。在这种情况下,我真的不希望在后台闲置一个控制台窗口。

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

7 个答案:

答案 0 :(得分:11)

虽然不完全是您提出的要求,但我过去通过使用FreeConsole pInvoke删除控制台窗口,实现了此行为的外观

将项目的输出类型设置为控制台应用程序。然后,您可以定义对FreeConsole的外部呼叫:

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

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

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

控制台窗口在启动时会短暂出现,但就我而言,这是可以接受的。

这有点像黑客虽然并且有难闻的气味,所以我会认真考虑你是否想沿着这条路走下去。

答案 1 :(得分:8)

来自'The Old New Thing'

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

你不能。

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

答案 2 :(得分:6)

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

注意:将项目类型设置为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());
            }
        }
编辑:感谢Adrian Bank的回答,FreeConsole()是一种更好的“分配”控制台窗口的方法,而不仅仅是最小化...

答案 3 :(得分:2)

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

答案 4 :(得分:1)

我认为答案是否定的,或者是我上次调查这个问题。

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

下看到此信息

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

你可以,但有一些缺点:

如果为子系统Windows编译,则可以防止启动此黑色窗口。

但是你必须通过AttachConsole(-1)手动将进程附加到调用控制台(cmd.exe) http://msdn.microsoft.com/en-us/library/windows/desktop/ms681952%28v=vs.85%29.aspx

仅凭这一点并不起作用。您还必须通过以下调用将三个标准流重定向到控制台:

// 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();

示例来自:http://cygwin.com/ml/cygwin/2004-05/msg00215.html

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

如果有办法阻止这个过程与子系统窗口分叉,请告诉我。

希望这有帮助。