C# 应用程序 GUI 和命令行

Posted

技术标签:

【中文标题】C# 应用程序 GUI 和命令行【英文标题】:C# application both GUI and commandline 【发布时间】:2011-11-04 03:31:07 【问题描述】:

我目前有一个带有 GUI 的应用程序。

是否可以从命令行使用相同的应用程序(没有 GUI 和使用参数)。

或者我是否必须为命令行工具创建一个单独的 .exe(和应用程序)?

【问题讨论】:

您完全可以使用相同的应用程序。只需将 string[] args 添加到您的 Main 方法中 或者,看看这个问题的答案:***.com/questions/1179532 因为您不是在询问从控制台读取输入(仅从命令行参数),所以这是一个骗局。 @PeeHaa:那么就像不运行Application.Run(new MyMainForm()); 一样简单。将它放在if 块中,如果你得到参数,不要运行那行代码。 @Merlyn Morgan-Graham:天哪,就是这么简单……甜! tnx 【参考方案1】:
    编辑您的项目属性以使您的应用程序成为“Windows 应用程序”(而不是“控制台应用程序”)。您仍然可以通过这种方式接受命令行参数。如果您不这样做,那么当您双击应用程序的图标时会弹出一个控制台窗口。 确保您的 Main 函数接受命令行参数。 如果您获得任何命令行参数,请不要显示该窗口。

这是一个简短的例子:

[STAThread]
static void Main(string[] args)

    if(args.Length == 0)
    
        Application.Run(new MyMainForm());
    
    else
    
        // Do command line/silent logic here...
    

如果您的应用还没有构建干净地进行静默处理(如果您的所有逻辑都卡在您的 WinForm 代码中),您可以hack silent processing in ala CharithJ's answer。

由 OP 编辑​​ 很抱歉劫持你的答案梅林。只想在这里为其他人提供所有信息。

要能够在 WinForms 应用程序中写入控制台,只需执行以下操作:

static class Program

    // defines for commandline output
    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(int dwProcessId);
    private const int ATTACH_PARENT_PROCESS = -1;

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    
        // redirect console output to parent process;
        // must be before any calls to Console.WriteLine()
        AttachConsole(ATTACH_PARENT_PROCESS);

        if (args.Length > 0)
        
            Console.WriteLine("Yay! I have just created a commandline tool.");
            // sending the enter key is not really needed, but otherwise the user thinks the app is still running by looking at the commandline. The enter key takes care of displaying the prompt again.
            System.Windows.Forms.SendKeys.SendWait("ENTER");
            Application.Exit();
        
        else
        
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new QrCodeSampleApp());
        
    

【讨论】:

完全不介意。请注意,如果您双击应用程序,Console.WriteLine 将使用此解决方案进入位桶。另外,如果您关心附加失败时,您可以查看Marshal.GetLastWin32Error @PeeHaa 谢谢,这很好用,但是对我来说它似乎在单独的线程中运行(例如,命令提示符立即返回,而无需等待在 Main 中开始的处理完成。是那是预期的吗? '使用 System.Runtime.InteropServices;'需要能够使用“DllImport”。 AttachConsole 的缺点是 cmd 调用将在连接控制台之前立即返回,因此在写入输出之前。这也是为什么最后需要一个额外的回车键的原因。如果你想在某处管道或重定向输出,你只会得到一个空输出。到目前为止,我还没有找到真正的解决方案。给定的解决方案不适用于我,但却是最接近的解决方案。 所以我正在尝试这样做,但我遇到的是当我从命令提示符运行我的应用程序并使用命令行参数运行时,它应该运行,但是,它将控制权返回给命令提示符立即。我期待它运行到最后并返回一个退出代码。我使用 Environment.Exit(-1) 表示错误,使用 (0) 表示成功,但它会立即返回,这将无法正常工作。【参考方案2】:

在您的 program.cs 类中,保持 Main 方法不变,但将 string[] Args 添加到主窗体中。比如……

    [STAThread]
    static void Main(string[] Args)
    
        ....
        Application.Run(new mainform(Args));
    

在 mainform.cs 构造函数中

    public mainform(string[] Args)
    
        InitializeComponent();

        if (Args.Length > 0)
         
             // Do what you want to do as command line application.
             // You can hide the form and do processing silently.
             // Remember to close the form after processing.
         
    

【讨论】:

+1;但是,如果您作为控制台应用程序运行,甚至不必费心去做Application.Run。隐藏窗口会起作用,但它是一个 hack :) 缺点是您将无法在控制台窗口中看到任何输出,因为应用程序没有附加真正的控制台窗口。 Console.WriteLine 不会产生任何可见的输出。【参考方案3】:

我是 C# 编程的新手。但我即兴创作了来自 OP 和 Merlyn 的代码提示。我在使用他们的代码提示时遇到的问题是,当我通过双击 app.exe 调用 app.exe 或从 CMD 调用它时,参数长度不同。当 app.exe 从 CMD 作为 CLI 运行时,app.exe 本身将成为第一个参数。下面是我的即兴代码,它既可以作为 app.exe 的 GUI 双击,也可以作为 CMD 的 CLI。

[STAThread]
    static void Main(/*string[] args*/)
    
        string[] args = Environment.GetCommandLineArgs();
        Console.WriteLine(args.Length);
        if (args.Length <= 1)
        
            //calling gui part
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new ACVSAppForm());
        
        else
        
            //calling cli part                
            string opt = args[1];
            //Console.WriteLine(args[0]);                
            if(opt == "LastBuild")
            
                if(args.Length == 3)
                
                    var defSettings = Properties.Settings.Default;
                    defSettings.CIBuildHistPath = args[2];
                
                else
                
                    //
                
                CIBuildParser cibuildlst = new CIBuildParser();
                cibuildlst.XMLParser();
            
        

    

我希望这对某人有所帮助。我的解决方案的唯一缺点是当 app.exe 作为 GUI 运行时,它将打开一个 CMD 作为控制台输出窗口。但这对我的工作来说没问题。

【讨论】:

【参考方案4】:

没有足够的积分来评论。我想在接受的解决方案中添加 [DllImport("kernel32.dll")] 在使用 mingw 调用程序时不需要写入控制台,这似乎是一个 windows/dos 问题。

【讨论】:

【参考方案5】:

您可能需要将您的应用程序构建为控制台应用程序,确定您在“操作”上所做的操作(例如单击按钮)到单独的类中,包括一个可以在没有提供命令行参数时显示的表单,并通过将事件路由到“Action”类中的常用方法来处理事件。

【讨论】:

不要让它成为控制台应用程序。否则,当您将其作为 GUI 启动时,会弹出一个控制台。【参考方案6】:

我认为这是可能的,只需将您的子系统设置为“控制台”,您将看到一个控制台窗口以及 GUI 窗口。

但是为了接受来自控制台窗口的命令,我想你必须创建一个额外的线程来完成它。

【讨论】:

这不是一个好的选择,因为如果他们通过双击文件图标启动它,它将产生一个额外的控制台。此外,您不一定必须生成另一个线程 - 例如,如果您通过命令行参数传递“命令”。

以上是关于C# 应用程序 GUI 和命令行的主要内容,如果未能解决你的问题,请参考以下文章

如何把命令行程序封装成有GUI的程序?

命令行程序增加 GUI 外壳

如何为命令行程序制作 gui?

第1课 - GUI 程序原理分析

从命令行自动执行 iOS monotouch GUI 测试

001_GUI程序原理分析