如何创建一个C#应用程序来决定自己是显示为控制台还是窗口应用程序?

Mat*_*hew 46 .net c# wpf winforms

有没有办法启动具有以下功能的C#应用​​程序?

  1. 它通过命令行参数确定它是窗口控制还是控制台应用程序
  2. 当它被要求窗口化时它不显示控制台,并且当它从控制台运行时不显示GUI窗口.

例如,

myapp.exe /help
将输出到您使用的控制台上的stdout,但是
myapp.exe
本身将启动我的Winforms或WPF用户界面.

到目前为止,我所知道的最佳答案涉及两个独立的exe和使用IPC,但这感觉非常hacky.


我可以使用哪些选项并进行权衡以获得上述示例中描述的行为?我也对Winform特定或WPF特定的想法持开放态度.

Eri*_*lje 57

使应用程序成为常规Windows应用程序,并在需要时动态创建控制台.

此链接的更多详细信息(下面的代码)

using System;
using System.Windows.Forms;

namespace WindowsApplication1 {
  static class Program {
    [STAThread]
    static void Main(string[] args) {
      if (args.Length > 0) {
        // Command line given, display console
        if ( !AttachConsole(-1) ) { // Attach to an parent process console
           AllocConsole(); // Alloc a new console
        }

        ConsoleMain(args);
      }
      else {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
      }
    }
    private static void ConsoleMain(string[] args) {
      Console.WriteLine("Command line = {0}", Environment.CommandLine);
      for (int ix = 0; ix < args.Length; ++ix)
        Console.WriteLine("Argument{0} = {1}", ix + 1, args[ix]);
      Console.ReadLine();
    }

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AllocConsole();

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AttachConsole(int pid);

  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法最大的问题似乎是当你从shell启动时,进程会立即返回到启动控制台.在这种情况下,当您使用该shell /控制台时,stdout开始写入其他文本.如果有办法避免这种情况会非常方便,但我还没有找到任何东西. (9认同)

Mik*_*chs 14

我基本上按照Eric的回答中描述的方式执行,另外我使用FreeConsole分离控制台并使用SendKeys命令来获取命令提示符.

    [DllImport("kernel32.dll")]
    private static extern bool AllocConsole();

    [DllImport("kernel32.dll")]
    private static extern bool AttachConsole(int pid);

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

    [STAThread]
    static void Main(string[] args)
    {
        if (args.Length > 0 && (args[0].Equals("/?") || args[0].Equals("/help", StringComparison.OrdinalIgnoreCase)))
        {
            // get console output
            if (!AttachConsole(-1))
                AllocConsole();

            ShowHelp(); // show help output with Console.WriteLine
            FreeConsole(); // detach console

            // get command prompt back
            System.Windows.Forms.SendKeys.SendWait("{ENTER}"); 

            return;
        }

        // normal winforms code
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());

    }
Run Code Online (Sandbox Code Playgroud)

  • 这应该是答案.SendKeys非常重要. (3认同)

The*_*TXI 7

写两个应用程序(一个控制台,一个窗口),然后编写另一个较小的应用程序,根据给定的参数打开其他应用程序之一(然后可能会关闭自己,因为它将不再需要)?


Ant*_*ien 5

我通过创建两个单独的应用程序来完成此操作.

使用以下名称创建WPF应用程序:MyApp.exe.并使用以下名称创建控制台应用程序:MyApp.com.当您在命令行中键入应用程序名称时,MyApp或者MyApp /help(没有.exe扩展名)时,具有.com扩展名的控制台应用程序将优先.您可以让控制台应用程序MyApp.exe根据参数调用.

这正是devenv的行为方式.devenv在命令行输入将启动Visual Studio的IDE.如果传递参数/build,它将保留在命令行中.