How to own console for time of program execution? - c#

I'm trying to write a program, that works in console or GUI mode, depending on execution parameters. I've managed to write following sample code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace wfSketchbook
{
static class Program
{
[DllImport("Kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AttachConsole(int processId);
[DllImport("Kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport("Kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeConsole();
private const int ATTACH_PARENT_PROCESS = -1;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
if (!AttachConsole(ATTACH_PARENT_PROCESS))
AllocConsole();
Console.WriteLine("Welcome to console!");
Console.ReadKey();
FreeConsole();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
}
It generally works, however when program is called from the system command-line, the cmd seems not to be aware, that program works in console mode and exits immediately:
d:\Dokumenty\Dev\C#\Projekty\Win32\Sketchbook\wfSketchbook\bin\Debug>wfSketchbook.exe test
d:\Dokumenty\Dev\C#\Projekty\Win32\Sketchbook\wfSketchbook\bin\Debug>Welcome to console!
d:\Dokumenty\Dev\C#\Projekty\Win32\Sketchbook\wfSketchbook\bin\Debug>
I'd rather expect following output:
d:\Dokumenty\Dev\C#\Projekty\Win32\Sketchbook\wfSketchbook\bin\Debug>wfSketchbook.exe test
Welcome to console!
d:\Dokumenty\Dev\C#\Projekty\Win32\Sketchbook\wfSketchbook\bin\Debug>
How may I correct this problem?

There is no ideal solution for this. Cmd.exe is only going to automatically wait for the program to complete if it can see that the .exe is a console mode app. Which won't be the case for your app. One workaround is to tell it to wait:
start /wait yourapp.exe [arguments]
The other is to always use AllocConsole(). Which the side-effect that it creates a second console window. Changing the application type to Console then calling FreeConsole() is not ideal either, the flash of the window is quite noticeable. Pick your poison.

There isn't any reliable way to make a Windows application a console and a GUI. Your program is a Windows application - so Windows launches you outside of the console window - when your program starts you aren't attached to the console window.
You could change your project output to a Console application in the project's properties. But then you would always get a console window. Windows could see that your application was marked as a console application and create a console even before you ran.
See this blog post for more information and links to some work arounds.

Related

FreeConsole() does not detach the process

I have already read this similar quesiton but the solution accepted in that question is not working for me.
I have a WinForm application (called FormPlusConsoleApp) that works as a console application if some arguments are passed by the calling program.
I need to provide status messages from the program FormPlusConsoleApp to the console therefore, I attach to the console at the very beginning of the program.
PROBLEM: After executing the required job, the program should exit with an exit code 0/1 and should completely detach to the console without any user interaction.
I am already calling the FreeConsole() method as suggested in this similar quesiton but at the end, a blinking cursor appears on the command prompt (as shown in the screenshot) and the user must press a button to completely exit.
Sample Working Program:
using System;
using System.Windows.Forms;
using System.IO;
namespace FormPlusConsoleApp
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
System.Windows.Forms.MessageBox.Show("Attach the debugger now...");
if (args.Length == 0) //form version
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormApp());
}
else //start console version
{
// case args.Length > 0
SampleConsoleExecution();
}
}
static void SampleConsoleExecution()
{
//attach to the console
bool isAttached = AttachConsole(-1);
//Sample Message
Console.WriteLine(Environment.NewLine + "Console process started...");
//do something
Console.WriteLine(Environment.NewLine + "Exit process!");
//Free console
FreeConsole(); //<<<<<<<<<--------blinking cursor appears on the console but the user still have to press the "ENTER" button
}
//To attach to the console (parent)
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
//To free from the attached console
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
}
}
PS: I understand that the best approach is to have separate WinForm and console applications that use the same business logic. Unfortunately, that's not an option for me. The above code is just MWE to test the problem.
As written in this blog post by Raymond Chen and this answer you can't have an app that is both, console and windows app.
There are few workarounds, the approach that worked for me is to add the following code at the end of the main function:
SendKeys.SendWait("{ENTER}");
In order to set the exit code, you could use Environment.Exit:
Environment.Exit(0);

Console Application to be run as GUI as well

Before anyone marks this as Duplicate, Please read
I have a process which is Windows Application and is written in C#.
Now I have a requirement where I want to run this from console as well. Like this.
Since I need to show output to console, so I changed the application type to Console Application
Now the problem is that, whenever user launches a process from Windows Explorer (by doubling clicking). Console window also opens in behind.
Is there is way to avoid this ?
What I tried after #PatrickHofman's help.
Followed how to run a winform from console application?
But I still have problems
When I do this https://stackoverflow.com/a/279811/3722884, the console opens in new window. I don't want that.
When I do this https://stackoverflow.com/a/11058118/3722884, i.e. pass -1 to AllocConsole there are other problems which occur, as mentioned in the referred link.
OK I thought I'd have a play at this as I was curious.
First I updated the Main method in Program.cs to take arguments so I could specify -cli and get the application to run on the command line.
Second I changed the project's output type to "console application" in the project properties.
Third I added the following methods to Program.cs
private static void HideConsoleWindow()
{
var handle = GetConsoleWindow();
ShowWindow(handle, 0);
}
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
Fourth I call HideConsoleWindow as the first action in non-CLI mode.
After these steps my (basic) application looks like:
[STAThread]
static void Main(string[] args)
{
if (args.Any() && args[0] == "-cli")
{
Console.WriteLine("Console app");
}
else
{
HideConsoleWindow();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
Then if I open the program on the command line with the -cli switch it runs as a command line application and prints content out to the command line and if I run it normally it loads a command line window (extremely) briefly and then loads as a normal application as you'd expect.

How to show the console on a C# program with Windows application output type

I have a C# Console application project where the output type is set to "Windows application". This is so the console does not flash up at the start of the program.
However i also want to allow a help command line argument which will display details about the program if you run it from the command line with "/?" as an argument.
Is there a way to have the program run as a windows application normally but show a console if the help argument is passed?
EDIT - After reading the answers and a similar one at This question (this question assumes you are running with a console application output type) I am using this solution.
[DllImport(Kernel32_DllName)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
static void Main(string[] args)
{
if(args.Contains("/?"))
{
AllocConsole();
Console.WriteLine("helpText");
Console.ReadLine();
var handle = GetConsoleWindow();
//Hides console
ShowWindow(handle, SW_HIDE);
}
}
I have not found a way to do exactly as you are asking, but you can have a console open up depending on the input. For example:
class Program
{
private const string Kernel32_DllName = "kernel32.dll";
[DllImport(Kernel32_DllName)]
private static extern bool AllocConsole();
static void Main(string[] args)
{
if (args[0] == "/")
{
AllocConsole();
Console.WriteLine("Details");
Console.ReadKey();
//cases and such for your menu options
}
That will open a console that you can use if you follow the run command with a / even though the output type of the project is a Windows Application.
Is there a way to have the program run as a windows application normally but show a console if the help argument is passed?
For what you want, learn about using command line arguments here.
Basically declare Main to accept arguments as an array of string:
static void Main(string[] args)
Use a simple dialog form to display the help message or even a MessageBox which is a very simple dialog form.
This gives you much better control rather than trying to cobble something together that wasn't really meant to be put together.
When I need to do stuff like this, I usually make my app a console app. I then parse the args if any in main and decide if I'm going to hide the console window and launch my UI or write to the console.
Hiding a window is fairly straightforward. See How to hide / unhide a process in C#? for an example.

Reboot console application

How can i reboot my C# console application like in Java when programm still work in same console, without creating new one.
I tried to start new application with Process.UseShellExecute = false and kill current process from newly created, but i can kill parent process from child using this. I tried to kill current process after creating new, but also it doesnt work.
There is no straightforward way to do this, however you can simulate this behavior:
Change your application from console application to Windows application.
Create a console for the first instance of your application
Start a new instance of your application and attach to the console created in step 2.
Exit the first instance.
It is important not to forget to change the application type to Windows application.
The following code will restart the application until you press Ctrl+C:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;
class Program
{
[DllImport("kernel32", SetLastError = true)]
static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
const uint ATTACH_PARENT_PROCESS = 0x0ffffffff;
[STAThread]
static void Main(string[] args)
{
if (!AttachConsole(ATTACH_PARENT_PROCESS))
{
AllocConsole();
}
Console.WriteLine("This is process {0}, press a key to restart within the same console...", Process.GetCurrentProcess().Id);
Console.ReadKey(true);
// reboot application
var process = Process.Start(Assembly.GetExecutingAssembly().Location);
// wait till the new instance is ready, then exit
process.WaitForInputIdle();
}
}

How do I write to command line from a WPF application?

Hi I know how to write to console but if I write to console in my program and call my program from the command line it won't display anything.
How do I make it so that when I say Console.WriteLine or Console.Out.Writeline ir prints to the command prompt from which it was called and not somewhere else?
Once again I know how to do Console.WriteLine so it's not that :-p unless I'm doing it wrong.
From what I can tell it's probably something to do with Console.SetOut(TextWriter t)
this is a WPF application and I need it to post its data to the command line while still retaining the GUI at startup. I've triple checked and my code hits the print lines, I can actually see the lines being printed to the Visual Studio output window, it just won't display in the command line when I run it manually without VS.
If possible I need to conditionally have the console display. ie if run from command line (or even with command arguments), display or post to the prompt, otherwise do not.
This is actually trivial:
public void WriteToConsole(string message)
{
AttachConsole(-1);
Console.WriteLine(message);
}
[DllImport("Kernel32.dll")]
public static extern bool AttachConsole(int processId);
This method will write your message to the console if your program was started from the command line, otherwise it will do nothing.
If you want to use an alternative output mechanism when you weren't started from the command line you can do it this way:
public void WriteToConsole(string message)
{
_connected = _connected || AttachConsole(-1);
if(_connected)
Console.WriteLine("Hello");
else
... other way to output message ...
}
bool _connected;
[DllImport("Kernel32.dll")]
public static extern bool AttachConsole(int processId);
The full code for this particular task is:
public static void WriteToConsole(string message)
{
AttachConsole(-1);
System.Console.WriteLine(message);
SendKeys.SendWait("{ENTER}");
FreeConsole();
}
[DllImport("Kernel32.dll")]
private static extern bool AttachConsole(int processId);
[DllImport("kernel32.dll")]
private static extern bool FreeConsole();
All credits goes to Ray Burns & Scott Marlowe.
Set the project type to "Console Application" instead of "Windows Application". This will cause the Application to attach to the console from which it was launched (or create a console if there was not one already).

Categories