views:

465

answers:

6

Hi,

I've read a few topics about programs that combine WinForms and console applications but it seems my question hasn't been solved yet. Is it possible to run a program from cmd-line and to be able to control the app via forms and via cmd-line commands? It means:

  • for ordinary users of the app to control the app via (win) forms,
  • for debugging and advanced users to control the app via console (and optionally see what's happening in WinForms))

I know that what I want is quite a big deal and it will probably mean a lot of work but still I would like to know how to do it properly.

Thanks!

A: 

I remember seeing IronPython being used in a demo controlling WinForms from Python's command line interface (IDLE).

Edit: I could not find the original video but this one should show what possible without too much effort. See this video and jump to 19:00

Philip Fourie
It is interesting, thank you! But I'm looking for a solution that doesn't use any new tools.
MartyIX
Added a video link to post. Before dismissing the idea because of new tools, have a look it might save you a lot of time and provide with powerful infrastructure to do want to you want. Alternatively you might want look at PowerShell instead of IronPython if that feels closer to home.
Philip Fourie
A: 

This would be possible. You will have to look into threading the WinForm, possibly with the use of a separate AppDomain within the same process. You might look into creating a proxy object (a kind of message class inheriting MarshalByRefObject).

dboarman
+1  A: 

You just need to start your WinForms app with an ApplicationContext instead of a Form itself.

You are than not depending on the mainform to be shown and can act like an console-application .

You could also just create a command line executable and link with the winforms libraries yourself to use them.

Another way would be to use some kind of starter, that fires up the winforms app, and a command line tool that communicates with the winforms app over local networking, or other inter process communication, DBUS or similiar systems - many ways lead to rome...

BeowulfOF
A: 

Normally when looking at your application, you have an UI layer and a business layer (and a Data layer, and who knows many more layers). You can think of the Console client as an UI layer (with simple command inputs) and the Winform client as another one.

Simply check at application startup for commandline arguments. If there are arguments specified instantiate the simple Console classes, otherwise instantiate the (probably more complex) Winform classes.

If you want your changes to reflect in the WinForms application (while controlling it from the Console application) setup your applications as much as you can with databinding. Let your business layer reflect what's actually going on in your application.

Zyphrax
A: 

Yes, what you want is very possible. You have options. Some I can think of...:

  1. Use UI Automation to write a controller app that can connect to the Forms app and control it. This is new in Vista. There are managed classes packaged in the System.Windows.Automation namespace, which first shipped in WPF, which arrived in .NET 3.0. (Now that I think about it, I'm not sure "new in Vista" is true. It may be "new in .NET 3.0" which implies it also works on WinXP. Hmmm....) UI Automation requires no code change to the WinForms app, but it can be sort of low-level, because you need to program each mouse click or cut/paste. See the answer to Is there a way to control a third party exe from vb.net?.

  2. Modify your winforms app to expose its function via a WM_COPYDATA interface. Then your client app can communicate with it. Again, the model here is 2 distinct apps, one of which can control or interrogate the other. The .NET Reflector tool is a good example of this approach. There's a ReflectorController, available as part of the ReflectorAddins project on codeplex. The controller is a command-line tool, that can send WM_COPYDATA messages to Reflector, to tell it to open a new assembly, navigate to a particular class, and so on.
    .
    The code for the controller: http://reflectoraddins.codeplex.com/sourcecontrol/network/Show?projectName=reflectoraddins&changeSetId=29526#19979
    .
    This approach will work for any winform app. You will need to override the WndProc method. To see how, check this codeproject article.
    .
    I also used this approach to build a winforms-based progress monitor that can visually display the progress of long-running tests.

  3. Within your app, expose a COM server object that can be programmed. This is exactly how Microsoft exposes Office function to apps. Office Automation allows any COM-capable program (C#, VBScript, powershell, Perl, PHP, etc) to "drive" office apps. The Office app is visible while that is happening. This approach would also require additional code in your WinForms app; specifically you have to host a COM object and hook it up to your UI layer. This may be preferable if you want maximum flexibility for superusers - they can write their own scripts to drive that component.

I'm sure there are other options.

Cheeso
+1  A: 

It isn't difficult, just P/Invoke the AllocConsole() API function to create your own console. For example, make your Program.cs source code file look like this:

  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();
  }
Hans Passant
I do not understand how a developer runs back at native API so fast while working in managed code... first search the framework, really there are only very few needs for native API access...
BeowulfOF
@BeowulfOF: please show us how you create a console window on demand.
Hans Passant
Why should you? Just let your Winforms-App startup again, and instead of firing up the mainform pipe the commandline parameter to the already running application - ways are there more than enough, all managed possible.
BeowulfOF
Thank you, AllocConsole is what I was looking for. I've accomplished my task via combination of code above and with usage of MVP pattern - sometimes it is tedious work but it works okey.
MartyIX