C#中的Windows Forms和控制台命令

8
我已经阅读了几篇关于结合Windows Forms和控制台应用程序的文章,但似乎我的问题还没有得到解决。是否可以从cmd-line运行程序,并能够通过窗体和cmd-line命令控制应用程序?这意味着:

  • 对于应用程序的普通用户,通过(Windows Forms)窗体来控制应用程序。
  • 对于调试和高级用户,通过控制台来控制应用程序(并可选择查看Windows Forms中发生的情况)。

我知道我想要的是相当大的一笔交易,这可能意味着很多工作,但我仍然想知道如何正确地做到它。


你是否构想过一个单一的应用程序,它可以呈现表单界面,并且还可以在需要时“弹出”控制台?还是你正在构想一个Forms应用程序,可以通过某些可编程接口从任意其他应用程序进行控制? - Cheeso
6个回答

5

这并不难,只需要使用P/Invoke调用AllocConsole() API函数来创建自己的控制台。例如,将您的Program.cs源代码文件更改为以下内容:

  static class Program {
    [STAThread]
    static void Main() {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
#if DEBUG
      CreateConsole();
#endif
      Application.Run(new Form1());
    }

    static void CreateConsole() {
      var t = new System.Threading.Thread(() => {
        AllocConsole();
        for (; ; ) {
          var cmd = Console.ReadLine();
          if (cmd.ToLower() == "quit") break;
          // Etc...
        }
        FreeConsole();
      });
      t.IsBackground = true;
      t.Start();
    }
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AllocConsole();
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool FreeConsole();
  }

我不明白开发人员在托管代码中如何如此快速地返回到本机API...首先搜索框架,实际上只有非常少的需要访问本机API... - Oliver Friedrich
@BeowulfOF:请展示一下如何按需创建控制台窗口。 - Hans Passant
为什么你要这样做呢?只需让你的Winforms应用程序重新启动,而不是启动主窗体,将命令行参数传递给已经运行的应用程序 - 有很多方法可以实现这一点,所有方式都可以管理。 - Oliver Friedrich
谢谢,AllocConsole正是我在寻找的。我通过上面的代码和MVP模式的使用完成了我的任务 - 有时候这是繁琐的工作,但它能够正常工作。 - MartyIX

1

你只需要使用ApplicationContext来启动你的Windows Forms应用程序,而不是直接使用一个窗体。这样你就不依赖于主窗体的显示,可以像控制台应用程序一样运行。

你也可以创建一个命令行可执行文件,并自己链接Windows Forms库以使用它们。

另一种方法是使用某种启动器来启动Windows Forms应用程序,然后使用一个命令行工具通过本地网络或其他进程间通信方式(如D-Bus或类似系统)与Windows Forms应用程序进行通信 - 有多种方法可以达到目的...


1

是的,你想要的非常可能实现。你有选择。我能想到的一些选择有:

  1. 使用UI Automation编写一个控制器应用程序,可以连接到Windows Forms应用程序并控制它。这是在Windows Vista中新增的功能。在System.Windows.Automation命名空间中打包了托管类,这些类首次出现在.NET 3.0中,该版本随WPF一起发布。(现在我想想,我不确定“在Windows Vista中新增”是否正确。它可能是“在.NET 3.0中新增”,这意味着它也适用于Windows XP。嗯....)UI Automation不需要对Windows Forms应用程序进行任何代码更改,但它可能有点低级,因为您需要为每个鼠标单击或剪切/粘贴编程。请参见Stack Overflow问题“有没有一种方法可以从VB.NET控制第三方EXE文件?”的答案

  2. 修改您的Windows Forms应用程序,通过WM_COPYDATA接口公开其功能。然后,您的客户端应用程序可以与其通信。同样,这里的模型是两个不同的应用程序,其中一个可以控制或查询另一个。.NET Reflector工具就是这种方法的一个很好的例子。有一个ReflectorController,作为CodePlex上的ReflectorAddins项目的一部分可用。该控制器是一个命令行工具,可以向Reflector发送WM_COPYDATA消息,告诉它打开一个新的程序集,导航到特定的类等。

    控制器的代码: http://reflectoraddins.codeplex.com/sourcecontrol/network/Show?projectName=reflectoraddins&changeSetId=29526#19979

    这种方法适用于任何Windows Forms应用程序。您需要覆盖WndProc方法。要了解如何操作,请查看The Code Project文章使用WM_COPYDATA将数据发送到/从C++和C# Windows进程

    我还使用这种方法构建了一个基于Windows Forms的进度监视器,可以可视化显示长时间运行的测试的进度。

  3. 在您的应用程序中,公开一个可以编程的COM服务器对象。这正是Microsoft将Office功能公开给应用程序的方式。Office Automation允许任何支持COM的程序(C#,VBScriptPowerShell,Perl,PHP等)“驱动”Office应用程序。在此过程中,Office应用程序是可见的。如果您想要超级用户的最大灵活性,则可能需要在Windows Forms应用程序中添加其他代码;具体来说,您必须托管一个COM对象并将其连接到UI层。他们可以编写自己的脚本来驱动该组件,这可能更可取。

我相信还有其他选择。


+1 对于使用 WM_COPYDATA 方法并提供反射器插件示例链接的支持。 - Angshuman Agarwal

0

我记得看到过 IronPython 在演示中被用来控制 Windows Forms,从 Python 的命令行界面(IDLE)。

编辑: 我找不到原始视频了,但这个视频应该展示了不需要太多努力就可以实现的功能。请查看此视频 并跳转至 19:00。


很有趣,谢谢!但我正在寻找一种不使用任何新工具的解决方案。 - MartyIX
在帖子中添加了一个视频链接。在因为新工具而驳回这个想法之前,请看一下它,它可能会为您节省大量时间,并提供强大的基础设施来实现您想要的内容。或者,如果PowerShell更符合您的口味,您也可以考虑使用PowerShell而不是IronPython。 - Philip Fourie

0

这是可能的。您将需要研究如何在Windows Forms表单中进行线程处理,可能需要使用同一进程内的一个单独的应用程序域。您可以考虑创建一个代理对象(一种继承MarshalByRefObject的消息类)。


0
通常在查看应用程序时,您会有一个UI层和一个业务层(以及数据层和许多其他层)。您可以将控制台客户端视为UI层(具有简单的命令输入),将Windows Forms客户端视为另一个UI层。
只需在应用程序启动时检查命令行参数。如果指定了参数,请实例化简单的控制台类,否则实例化(可能更复杂的)Windows Forms类。
如果您希望更改反映在Windows Forms应用程序中(同时从控制台应用程序控制它),请尽可能使用数据绑定设置您的应用程序。让您的业务层反映应用程序中实际发生的情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接