Jeremy Foster
Jeremy Foster

Reputation: 4763

How to create a Windows Forms program that can also run at the command prompt

I've created a program that has two projects: a windows UI and an "engine". I would like to make it so that the user can execute the program from a command prompt passing in some arguments and the engine will automatically execute them and spit out the results. OR the user can launch the UI and choose all of their options via dropdown lists and such and then click a button to tell the engine to do it's work. I actually already have it working using something I found a long time ago, but I'm trying to see if there's an easier way. The way I found involves adding a Win32 class and creating externals to AllocConsole, FreeConsole, and AttachConsole from kernel32.dll. Is there an easier way? Thanks.

Upvotes: 4

Views: 1825

Answers (3)

Timwi
Timwi

Reputation: 66573

Create four separate configurations, two for GUI and two for Console:

DebugConsole, DebugGui, ReleaseConsole, ReleaseGui

The above screenshot is for solution configurations. You’ll have to do the same again for the project (in the above screenshot the project that has those four configurations is Rummage). Here is an excerpt from Rummage.csproj:

[...]
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugGui|AnyCPU' ">
    <OutputType>WinExe</OutputType>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseGui|AnyCPU' ">
    <OutputType>WinExe</OutputType>
    <Optimize>true</Optimize>
    <DefineConstants>TRACE</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugConsole|AnyCPU'">
    <OutputType>Exe</OutputType>
    <DefineConstants>DEBUG;TRACE;CONSOLE</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseConsole|AnyCPU'">
    <OutputType>Exe</OutputType>
    <DefineConstants>TRACE;CONSOLE</DefineConstants>
    <Optimize>true</Optimize>
  </PropertyGroup>
[...]

Notice especially:

  • The Console configurations have <OutputType>Exe</OutputType> (that makes them a console app) while the Release configurations have <OutputType>WinExe</OutputType>.

  • Both Console configurations have the CONSOLE constant defined. That way you can use #if CONSOLE [...] #else [...] #endif to have console-/GUI-specific code. For example, the Main method might look like this:

    [STAThread]
    static int Main(string[] args)
    {
        #if CONSOLE
            return MainConsole(args);
        #else
            return MainGui(args);
        #endif
    }
    

    ... and then you can have the WinForms stuff in MainGui and the command-line parsing stuff in MainConsole.

This way you can run (and debug) either the GUI or the console version in Visual Studio, while in a build script you can simply build all of them (and into different directories or different EXE file names).

Upvotes: 1

John Saunders
John Saunders

Reputation: 161773

It's even simpler. Create a Console application. It will parse the command line to get the parameters, then will call your engine.

Let the WinForms application worry about GUI, let the Console application worry about the command-line.

Upvotes: 1

Davide Piras
Davide Piras

Reputation: 44595

it's simple, make your windows forms application and in the Main method check the command line parameters and in case your parameters are there, instead of calling

Application.Run(new Form1());

simply call your engine and start processing.

it's important to code your engine properly and have also the UI using the same engine when the user is starting those commands from the user interface, so to avoid any useless code duplication.

we use this approach in many programs and we are satisfied, if you do not call Application.Run(...) your program will simply terminate when the Main method ends.

Upvotes: 3

Related Questions