我想制作一个C#程序,它可以作为命令行界面或图形用户界面应用程序运行,这取决于传递给它的标志。这可以做到吗?
我已经找到了这些相关的问题,但它们并不完全涵盖我的情况:
发布于 2009-01-29 23:54:32
Jdigital's answer指出了Raymond Chen's blog,它解释了为什么不能同时拥有既是控制台程序又是非控制台*程序的应用程序:在程序开始运行之前,操作系统需要知道要使用哪个子系统。一旦程序开始运行,就来不及返回并请求另一种模式。
Cade's answer指向了an article about running a .Net WinForms application with a console。它使用在程序开始运行后调用AttachConsole的技术。这样做的效果是允许程序写回启动程序的命令提示符的控制台窗口。但那篇文章中的评论指出了我认为是一个致命的缺陷:子进程并不真正控制控制台。控制台继续代表父进程接受输入,并且父进程不知道在使用控制台进行其他操作之前,它应该等待子进程完成运行。
陈的文章指向了an article by Junfeng Zhang that explains a couple of other techniques。
第一个是devenv使用的。它的工作原理实际上是有两个程序。一个是devenv.exe,它是主图形用户界面程序,另一个是devenv.com,它处理控制台模式的任务,但是如果以非控制台的方式使用它,它会将其任务转发给devenv.exe并退出。该技术依赖于Win32规则,即当您键入不带文件扩展名的命令时,会优先选择com文件而不是exe文件。
Windows脚本宿主在这方面有一个更简单的变体。它提供了两个完全独立的二进制文件: wscript.exe和cscript.exe。同样,Java为控制台程序提供java.exe,为非控制台程序提供javaw.exe。
俊峰的第二种技术是ildasm使用的。他引用了ildasm的作者在两种模式下运行时所经历的过程。归根结底,它的作用如下:
仅仅调用FreeConsole来使第一个实例不再是控制台程序是不够的。这是因为启动该程序的进程cmd.exe“知道”它启动了一个控制台模式的程序,并且正在等待该程序停止运行。调用FreeConsole会使ildasm停止使用控制台,但不会使父进程开始使用控制台。
因此,第一个实例会自动重新启动(我想是通过一个额外的命令行参数)。当您调用CreateProcess时,有两个不同的标志可供尝试,DETACHED_PROCESS and CREATE_NEW_CONSOLE,这两个标志中的任何一个都将确保第二个实例不会附加到父控制台。之后,第一个实例可以终止并允许命令提示符继续处理命令。
这种技术的副作用是,当您从GUI界面启动程序时,仍然会有一个控制台。它会在屏幕上瞬间闪现,然后消失。
在俊峰的文章中,关于使用editbin来改变程序的控制台模式标志的部分,我认为是在转移注意力。您的编译器或开发环境应该提供一个设置或选项来控制它创建的二进制文件的类型。之后应该不需要修改任何东西。
因此,底线是,您可以拥有两个二进制文件,也可以拥有控制台窗口的瞬间闪烁。一旦你决定了哪一个是较小的邪恶,你可以选择你的实现。
*我说的是非控制台,而不是图形用户界面,否则这是错误的二分法。一个程序没有控制台并不意味着它有GUI。服务应用程序就是一个很好的例子。此外,一个程序可以有一个控制台和窗口。
https://stackoverflow.com/questions/493536
复制相似问题