C#:是否可以让单个应用程序根据开关充当控制台或 Windows 应用程序?

发布于 2024-08-12 08:50:43 字数 202 浏览 1 评论 0 原文

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

永不分离 2024-08-19 08:50:43

虽然不完全符合您的要求,但我过去已经通过使用外观 .FreeConsole" rel="noreferrer">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 
}

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

这有点像黑客,而且有难闻的气味,所以我会认真考虑你是否确实想走这条路。

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.

演出会有结束 2024-08-19 08:50:43

来自“旧新事物”

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

你不能。

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

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)

所谓喜欢 2024-08-19 08:50:43

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

注意:将项目类型设置为控制台应用程序

[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() 是使用控制台窗口“分配”的更好方法,而不仅仅是最小化它...

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

我是男神闪亮亮 2024-08-19 08:50:43

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

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.

囚我心虐我身 2024-08-19 08:50:43

我相信答案是否定的,或者这是我上次研究这个问题的时候。

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

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

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.

樱花坊 2024-08-19 08:50:43

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

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.

流星番茄 2024-08-19 08:50:43

可以,但有一些缺点:

如果为 Windows 子系统进行编译,则可以防止启动时出现此黑窗口。

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

仅此一项并不能完成这项工作。您还必须通过这些调用将三个 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();

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

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

如果有一种方法可以防止该进程与子系统窗口分叉,请告诉我。

希望这有帮助。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文