Allocate a console for a WinForm application - c#

I use the following code to allocate a Console for a WinForm application. The Console window shows up successfully and the output is there. But when I close the Console window, my WinForm applicaion is closed at the same time. Why? I want to keep the WinForm window.
private void btn_to_console_Click(object sender, EventArgs e)
{
if (NativeMethods.AllocConsole())
{
lbl_console_alloc_result.Text = "Console allocation successfully!";
IntPtr stdHandle = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);
Console.WriteLine("from WinForm to Console!");
lbl_console_alloc_result.Text = Console.ReadLine();
}
else
lbl_console_alloc_result.Text = "Console allocation failed!";
}
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetStdHandle")]
public static extern System.IntPtr GetStdHandle(Int32 nStdHandle);
/// Return Type: BOOL->int
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "AllocConsole")]
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool AllocConsole();
Thanks in advance...

Closing a Console Window will shutdown any application -whether a console application, Windows Forms, native Windows app, or WPF application. This is a "feature" of Console windows.
If you don't want this behavior, you should, instead, just make a custom window to display your output instead of using a Console Window. Otherwise, you need to call FreeConsole instead of closing the Window to detach your application from the Console window.

Related

Bring multiple processes to foreground windows

I currently have a multi monitor app on the electron engine which opens a different window with separate content on each monitor. It uses 2 separate processes with the same name to display these windows, "home".
The app can then be used to launch different windows. One of these is called "game". This game opens a control style window on the main monitor, and then the actual game on the second monitor. Both of these are different processes both called "game".
We currently have a small C# console app that can be called and passed a string to try and bring these apps to the front which looks as below:
class Program
{
[DllImport("user32.dll")]
private static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
static void Main(string[] args)
{
BringToFront(args[0]);
}
private static void BringToFront(string title)
{
// Get a handle to the Calculator application.
Process[] processes = Process.GetProcessesByName(title);
if (processes.Length > 1)
{
foreach(Process process in processes)
{
IntPtr mainWindowHandle = process.MainWindowHandle;
if (mainWindowHandle == GetForegroundWindow()) return;
SetForegroundWindow(mainWindowHandle);
}
}
}
}
The problem is that this only ever brings 1 window to the front, not both.
I have researched this and found that it is due to the rules surrounding SetForegroundWindow, and unless I'm mistaken, when we set the first foreground window we are then not allowed to set any others as the console app/process that called the console app is no longer the foreground process.
Is there any way to accomplish bringing 2 separate windows to the front using a C# console app?

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 be dynamically either console application or Windows Application

I have a small application who should be executed in two modes: non UI or WPF Window. It should depend on command line arguments.
In each mode, I need to show some feedback log:
In WPF Window mode, WPF is going to take care of visualizing logs,
In no UI mode, I need a console to show logs. If my app have been started from a console (mainly cmd.exe), I'd like to use it without opening a new one. If my app have been started outside of a console (double click on explorer, a CreateProcess, ...), I need to create a new console to output my results and wait for a Readkey to close it.
I have found:
how I can create a new console:
How to open/close console window dynamically from a wpf application?,
how to get current console windows handle to show/hide it:
Show/Hide the console window of a C# console application
And I know I can statically choose between "Windows Application" or "Console Application" in project property.
Choosing "Windows Application", GetConsoleWindow() is always 0 and I don't see how to reuse a previous console.
Choosing "Console Application", I can reuse a previous console but when started from explorer in WPF Window mode, a console is created under my WPF main window.
The question is: how can an application be really dynamic? Either in WPF Window mode, with only a WPF windows (and no console at all) or in non UI, with only one console (starting one or a new created one).
It was a lot easier in Winforms, but its not too hard.
Start off with a WPF Application Project (not a console application project with WPF windows).
Create a new Program.cs class in the root directory, add the following code:
class Program
{
[DllImport("Kernel32")]
public static extern void AllocConsole();
[DllImport("Kernel32")]
public static extern void FreeConsole();
[DllImport("kernel32.dll")]
static extern bool AttachConsole(uint dwProcessId);
[STAThread]
public static void Main(string[] args)
{
bool madeConsole = false;
if (args.Length > 0 && args[0] == "console")
{
if (!AttachToConsole())
{
AllocConsole();
Console.WriteLine("Had to create a console");
madeConsole = true;
}
Console.WriteLine("Now I'm a console app!");
Console.WriteLine("Press any key to exit");
Console.ReadKey(true);
if (madeConsole)
FreeConsole();
}
else
{
WpfApplication1.App.Main();
}
}
public static bool AttachToConsole()
{
const uint ParentProcess = 0xFFFFFFFF;
if (!AttachConsole(ParentProcess))
return false;
Console.Clear();
Console.WriteLine("Attached to console!");
return true;
}
}
Now you have a console app or a WPF app. In the Properties, set the start up object as the Program.Main method. In the example above, WpfApplication1.App.Main is the old start up object (defined in the App.xaml.cs file).
Edit this misses one of your requirements about using the existing console and I will edit it as soon as I figure out how to stay in the same console window.
New Edit Now works to use the existing console!

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.

.Net Console Application that Doesn't Bring up a Console

I have a console application I'm using to run scheduled jobs through windows scheduler. All the communication to/from the application is in email, event logging, database logs. Is there any way I can suppress the console window from coming up?
Sure. Build it as a winforms app and never show your form.
Just be careful, because then it's not really a console app anymore, and there are some environments where you won't be able to use it.
Borrowed from MSDN (link text):
using System.Runtime.InteropServices;
...
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
...
//Sometimes System.Windows.Forms.Application.ExecutablePath works for the caption depending on the system you are running under.
IntPtr hWnd = FindWindow(null, "Your console windows caption"); //put your console window caption here
if(hWnd != IntPtr.Zero)
{
//Hide the window
ShowWindow(hWnd, 0); // 0 = SW_HIDE
}
if(hWnd != IntPtr.Zero)
{
//Show window again
ShowWindow(hWnd, 1); //1 = SW_SHOWNORMA
}
It's a hack, but the following blog post describes how you can hide the console window:
http://expsharing.blogspot.com/2008/03/hideshow-console-window-in-net-black.html
Schedule the task to run as a different user than your account and you won't get a window popping up . . .
Simply configure the Scheduled Task as "Run whether user is logged on or not".
Why don't you make the application a Windows Service?

Categories