53

I currently have an application with a GUI.

Would it be possible to use this same application from the commandline (without GUI and with using parameters).

Or do I have to create a separate .exe (and application) for the commandline tool?

8
  • you can absolutely use the same application. Just add string[] args to your Main method Commented Aug 26, 2011 at 0:10
  • Or, have a look at the answers to this question: stackoverflow.com/questions/1179532 Commented Aug 26, 2011 at 0:15
  • Since you're not asking about reading input from the console (only from command line parameters), this is a dupe. Commented Aug 26, 2011 at 0:17
  • 2
    @PeeHaa: It is as simple as not running the line Application.Run(new MyMainForm());, then. Place it in an if block, and if you get arguments, don't run that line of code. Commented Aug 26, 2011 at 0:57
  • 1
    @Merlyn Morgan-Graham: omg it's that simple... Sweet! tnx Commented Aug 26, 2011 at 0:58

5 Answers 5

69
  1. Edit your project properties to make your app a "Windows Application" (not "Console Application"). You can still accept command line parameters this way. If you don't do this, then a console window will pop up when you double-click on the app's icon.
  2. Make sure your Main function accepts command line parameters.
  3. Don't show the window if you get any command line parameters.

Here's a short example:

[STAThread] static void Main(string[] args) { if(args.Length == 0) { Application.Run(new MyMainForm()); } else { // Do command line/silent logic here... } } 

If your app isn't already structured to cleanly do silent processing (if all your logic is jammed into your WinForm code), you can hack silent processing in ala CharithJ's answer.

EDIT by OP Sorry to hijack your answer Merlyn. Just want all the info here for others.

To be able to write to console in a WinForms app just do the following:

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()); } } } 
Sign up to request clarification or add additional context in comments.

13 Comments

Don't mind at all. Note that Console.WriteLine will go the bit-bucket with this solution if you double-clicked on the app. Also, you can check Marshal.GetLastWin32Error if you care when the attach failed.
@PeeHaa Thanks, this works quite well, however it seems that for me it is running in a separate thread (e.g. the command prompt returns immediately without waiting for the processing that started in Main to complete. Is that expected?
'using System.Runtime.InteropServices;' is needed to be able to use 'DllImport'.
The drawback with AttachConsole is that the cmd call will return immediately before the console is even attached and therefore before the output is written. This is also the reason why you need an additional enter key at the end. If you want to pipe or redirect the output somewhere, you will only get an empty output. I have not found a real solution this far. The given solution is not applicable for me but is the closest one.
So I'm attempting to do just this but what I'm experiencing is when I run my application from a command prompt with command line arguments it runs as it should, however, it returns control to the command prompt right away. I'm expecting it to run until the end and return an exit code. I'm using Environment.Exit(-1) for errors and (0) for success but with it returning right away that's not going to work out correctly.
|
10

In your program.cs class keep the Main method as it is but add string[] Args to the main form. For example...

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

In mainform.cs constructor

 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. } } 

2 Comments

+1; But don't even bother doing Application.Run if you're running as a console app. Hiding the window will work, but it is a hack :)
The drawback is that you won't be able to see any output in the console window as there is no real console window attached to the application. Console.WriteLine will not produce any visible output.
2

I am new to c# programming. But I improvised the code hints from OP and Merlyn. The issue I faced when using their code hint was that the argument length is different when I call app.exe by double click on app.exe or when I call it from CMD. When app.exe is run as CLI from CMD then app.exe itself becomes the first arguments. Below is my improvised code which works satisfactory both as GUI double click of app.exe and as CLI from CMD.

[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(); } } } 

I hope this helps someone. The only drawback of my solution is when the app.exe is run as GUI, it will open a CMD as console output window. But this is OK for my work.

Comments

-2

You may need to structure your Application as a Console Application, identify what you do on "Actions" - like clicking of the button - into separate class, include a form that can be shown if there were no command line arguments supplied, and handle events by routing them to the common methods in your "Action" class.

1 Comment

Don't make it a console app. Otherwise a console will pop up when you launch it as a GUI.
-3

I think it is possible, just set your subsystem to "console", you will see a console window as well as the GUI window.

But in order to accept commands from the console window, I guess you will have to create an extra thread to do it.

1 Comment

This is not a good option because it will spawn an additional console if they launch it by double-clicking on the file icon. Also, you don't necessarily have to spawn another thread - for example, if you pass your "commands" via command line parameters.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.