C# application both GUI and commandline - c#

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?

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.
Make sure your Main function accepts command line parameters.
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());
}
}
}

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

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.

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.

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.

Related

How to get hidden form from task bar to front in C# winform? From class

I am doing it from a class, because I've got code to make it so only one instance can work. I've seen lots of forums and just cannot figure it out. I've tried all sorts of methods like Application.OpenForms etc, nothing is working. The last form which was closed will be hidden in the taskbar. I just want to be able to bring that hidden form.
namespace EncryptionDecryption
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
bool instanceCountOne = false;
using (Mutex mtex = new Mutex(true, "MyRunningApp", out instanceCountOne))
{
if (instanceCountOne)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Login("", ""));
mtex.ReleaseMutex();
}
else
{
MessageBox.Show("An instance of this application is already running in the taskbar", "Note");
mtex.ReleaseMutex();
Environment.GetCommandLineArgs();
//Trying to pass the loggedinusername and role to new instance of the program so dont have to sign in again...
}
}
}
}
Instead of using the above I used this which plays with threads to make sure I only have one instance and it will open that one instance only with new parameters to! Which i really needed for my next step!
https://social.msdn.microsoft.com/Forums/vstudio/en-US/a5bcfc8a-bf69-4bbc-923d-f30f9ecf5f64/single-instance-application?forum=csharpgeneral

C# Add Windows Form Application To A Console Application

I have a console application doing some things in the background, and I want to make it so that the user can change some things that the console application is doing.
I want to add a Windows Form Application to just get the user input and send it to the console application to use. I have looked and couldn't find what I'm looking for
I found this question - Add GUI to Existing Code in Visual Studio - but this didn't help me much.
I have this:
bool OnOrOff = true;
but I want to check if a check box from the windows form is checked instead of seting it to true like this:
on Windows Form the checkbox is named CheckOnOrOff and it is checked.
bool OnOrOff = CheckOnOrOff.Checked();
I assume that the user can change the settings while the console application is running and the effect should be taken immediately. Adding your winforms application as reference in console will not help since it's will be a different application. So this is what I suggest:
Make a new winforms application and change the output type from 'Windows Application' to 'Console Application' so we can see the console. Port your console logic proccess to the winforms project
Add a new static class which will hold flag between winforms and console. Example:
namespace FormWithConsole {
public static class SharedData {
public static bool Feature01 { get; set; }
}
}
Add a checkbox your Windows Form and add code bellow to the checkbox changed event:
private void checkBox1_CheckedChanged(object sender, EventArgs e) {
SharedData.Feature01 = checkBox1.Checked;
}
Add a button to start your console process, and use thread to start your console process as follow:
Thread thread;
private void button1_Click(object sender, EventArgs e) {
if (thread != null) {
try {
Console.WriteLine("Aborting current process");
thread.Abort();
thread = null
}
catch (ThreadAbortException) { }
}
ConsoleProcess process = new ConsoleProcess();
thread = new Thread(process.StartProcess);
thread.IsBackground = true;
thread.Start();
}
This is ConsoleProcess class, which hold your console logic
class ConsoleProcess {
public void StartProcess() {
while (true) {
if (SharedData.Feature01) {
// Do something here
}
Console.WriteLine("Regular process here...");
}
}
}
If you want the form minimized to system tray refer to minimize app to system tray
I think you should design a database to store the user input. Your console project and window project will run and manage by this database.
You can take input from windows form (by User) and then pass it to Console application by using parameter argument in Console Application.
The parameter of the Main method is a String array that represents the command-line arguments
So, if I had a console program (MyCApp.exe) like this:
class Program
{
static void Main(string[] args)
{
foreach (var arg in args)
{
Console.WriteLine(arg);
}
}
}
That I started at the command line like this:
MyCApp.exe Arg1 Arg2 Arg3 The Main method would be passed an array
that contained three strings: "Arg1", "Arg2", "Arg3".
If you need to pass an argument that contains a space then wrap it in quotes. For example:
MyCApp.exe "Arg 1" "Arg 2" "Arg 3"
Command line arguments commonly get used when you need to pass information to your application at runtime. For example if you were writing a program that pass basic information to copies a file from one location to another you would probably pass the two locations as command line arguments. For example:
MyCApp.exe C:\file1.txt C:\file2.txt Copyit
Here 'C:\file1.txt' is first Argument, 'C:\file2.txt' is first Argument, 'Copyit' is third Argument

Why does OpenFileDialogue cause failure in debug on a C# Forms Application?

I've been trying to find a solutions for this issue the past 2 days. Basically when I'm debugging my form app, I have a button with an onclick event handler. Here is the code in my handler.
private void btnBrowseReqDoc_Click(object sender, EventArgs e)
{
OpenFileDialog FileDlg = new OpenFileDialog();
FileDlg.InitialDirectory = m_ConfigFile.GetReqDocDir();
FileDlg.Filter = "All Files (*.*)|*.*|Word 97-2003 (*.doc)|*.doc|Word 2007 (*.docx)|*.docx";
FileDlg.FilterIndex = 1;
if (FileDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtWordReqDoc.Text = FileDlg.FileName;
SetProgressControls(false);
}
this.btnExecute.Enabled = CanEnableExecuteBtn();
lblStatus.Visible = !(CanEnableExecuteBtn());
}
About 60% to 70% of the time, this action will not complete. A partial window appears but at this point it is basically the window of death. I have to reboot to recover my machine. This problem doesn't seem that uncommon. Based on my research most people seem to feel this has to do with threading. My program.cs has always had this attribute set. Here is my program.cs code.
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
So is this just some kind of threading contention? Why does it work sometimes and not work other times?? Should the OpenFileDialogue be run in a background process perhaps?? I have a workaround for the issue while I debug (which is basically just paste in the file path), I just wanted to learn more about this behavior here if at all possible.

When add command line support to my Winforms app Is it better to use same EXE file or add new console application project?

I try to add command line support to my Winforms application so i changed this:
[STAThread]
static void Main(string[] args)
{
if (args.Length == 0)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
else
{
}
}
But i try to return string to the user in case the user insert the command MyExeFile.exe help to show the user all the command line options and i don't know how so i wonder maybe it's better to use other EXE file ?
You could see if the arguments contains "help". If it does, display a message to the user and then exit the app before loading the main form.
static void Main(string[] args)
{
if (args.ToList().Contains("help"))
{
MessageBox.Show("Help is on the way...");
return;
}
...
}
You'll need to add the following using directive:
using System.Linq;
If you want the help text to appear to show in a Console window, just create a form that looks like a console window.
Create a new Form, with a single TextBox in it, and configure the TextBox:
BackColor: Black
ForeColor: White
Dock: Fill
MultiLine: True
ReadOnly: True
Text: Whatever you want to show
Then show it using:
static void Main(string[] args)
{
if (args.ToList().Contains("help"))
{
new ConsoleLookalikeForm().ShowDialog();
return;
}
...
}
This took about 2 minutes to make:

How do I handle Command Line Arguments in Winforms if I don't want to load Main form?

I want to create an app that behaves as follows:
On no argument it displays the main form
On argument "a" does a job but the main form isn't loaded.
On argument "b" the form loads using the argument passed (load that document)
For the 1 and 3 I can handle the arguments in the form's constructor as follows:
public ConfigurationActionManagerForm()
{
InitializeComponent();
Environment.GetCommandLineArgs();
// do stuff with that argument
}
But this approach doesn't allow me to apply the behavior of 2. in the list.
In program.cs I can edit it to handle the arguments before the form is even created, but what is the correct approach on using Application.Run() if I don't want to pass a form? How am I going to inform Program class instance that I need to terminate or show a message that something went wrong or even show a little taskbar icon that the process is doing stuff (Think of it like the unzipping process).
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigurationActionManagerForm());
}
Would this approach from MSDN be correct to my application?
Do you mean in the same way that Visual Studio works?
If so then you can't do this in a normal Windows application - Visual Studio cheats.
The problem is that a Windows application can either be a Windows Forms application or a Console application, but it can't be both - its decided at compile time (for .Net applications this is in the project properties window). Your options are:
Make your application a Windows Forms application
In this case #1 and #3 will work perfecty, but for #2 you will find that you can't read from / write to the console (because there isn't one!). If your appliction doesn't need to give any feedback then this might be fine - do your work as you normally would and just don't display a form:
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
// Handle #2 here
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigurationActionManagerForm());
}
}
Make your application a console application
In this case #2 will work perfectly, however although #1 and #3 will work fine you will always have console window open in the background - if you close the console window your application will end.
Again this might be fine, but personally I find this to be a hack.
Cheat (do what Visual Studio Does)
Visual Studio cheats by having 2 separate applications - one is a Console Application and the other is a Windows Forms application. The easy solution is to leave it at that and require that users start a different executable when running the command line version (e.g. myprogram_g.exe and myprogram_w.exe).
Visual Studio goes one step further however and has a single entry point, devenv. It does this by using the fact that for compatability reasons the Windows shell will always run a .com file instead of a .exe if there is any ambiguity. Wheras all shortcuts etc.. point to the executable, if you run devenv on the command line the devenv.com application will run instead which uses magic to sort out whether or not it runs as a console or windows application.
My advice would be to create two different applications and leave it at that.
See How do I write a program that can be run either as a console or a GUI application? for more detail (make sure to read the comments which have additional useful suggestions).
Also see How to make an application as both GUI and Console application? for how ildasm does this.
You can call Application.Run() without a form instance.
That way, it will start the message loop without opening a form.
You can call MessageBox.Show() before calling .Run(), too.
You can even create and open a form, and then call Run() without specifying an argument - it just means that closing the form doesn't automatically exit the application.
E.g.
MessageBox.Show("Messaage!");
Form1 f = new Form1();
f.Show();
Application.Run();
As stated above, this way of doing Run() means that closing the forms doesn't automatically close the application. You need to handle this in the form's Close event handler. (Application.Exit())
MSDN online can help you out with this - check the help entry for Application.Run().
Basically you want a console applcation with a few changes.
Here's an example of how to get started, using a default aboutbox class:
using System;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("No Arguments");
}
else
{
if (args[0] == "a")
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new AboutBox1());
}
}
}
}
}
And AboutBox1 class:
using System.Reflection;
using System.Windows.Forms;
namespace ConsoleApplication1
{
partial class AboutBox1 : Form
{
public AboutBox1()
{
InitializeComponent();
this.Text = String.Format("About {0} {0}", AssemblyTitle);
this.labelProductName.Text = AssemblyProduct;
this.labelVersion.Text = String.Format("Version {0} {0}", AssemblyVersion);
this.labelCopyright.Text = AssemblyCopyright;
this.labelCompanyName.Text = AssemblyCompany;
this.textBoxDescription.Text = AssemblyDescription;
}
#region Assembly Attribute Accessors
public string AssemblyTitle
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title != "")
{
return titleAttribute.Title;
}
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
}
}
public string AssemblyVersion
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
public string AssemblyDescription
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyDescriptionAttribute)attributes[0]).Description;
}
}
public string AssemblyProduct
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyProductAttribute)attributes[0]).Product;
}
}
public string AssemblyCopyright
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
}
}
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
#endregion
private void okButton_Click(object sender, EventArgs e)
{
Close();
}
}
}
I found a neat and simple to implement solution using the example in my question provided by microsoft.
I created this application context class that is responsible for everything in the application and I use this instead of a form in the Application.Run() as shown below.
To achieve the behavior in the question, I am using a second form that is hidden and only the taskbar icon is shown. If the user wants to see how the process is doing, they can click the taskbar icon and see the logging window, which is actually the ConfigurationApplierForm in the example bellow.
class AnApplicationContext: ApplicationContext
{
private Form _currentForm;
Note the constructor is private, the main is inside this class and declared static.
private AnApplicationContext()
{
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
// choose which form to show based on arguments
if(Environment.GetCommandLineArgs().Contains("-apply"))
{
_currentForm = new ConfigurationApplierForm();
}
else
{
_currentForm = new ConfigurationActionManagerForm();
}
// initialize the form and attach event handlers
_currentForm.FormClosed += new FormClosedEventHandler(this.OnCurrentFormClosed);
_currentForm.ShowDialog();
}
Main is here, a little bit different from the original. Notice the argument in the Run method
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// context is passed instead of a form
Application.Run(new AnApplicationContext());
}
private void OnCurrentFormClosed(object sender, EventArgs e)
{
ExitThread();
}
private void OnApplicationExit(object sender, EventArgs e)
{
/* is there anything to do when all forms are closed
and the application is going to die?*/
}
}
Also, we need to tell the project that this is the startup project.
Project Properties -> Application -> Startup Project

Categories

Resources