Reboot console application - c#

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

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 own console for time of program execution?

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.

How do I prevent a C# console application from taking priority as the active window?

I'm sorry if this has been asked but I cannot find an answer to it. I may not be searching the right terms.
I have a console program that needs to be run in the background. The user needs the console to stay open white it runs, but need it to not become the active window when it starts. They would like to continue what they are currently working on and not have to minimize the console every time it starts.
This console application runs multiple times, each time with a new console window. How can I "hide" the console behind the current running task/window?
You can programmatically minimize/restore console windows using below code:
using System;
using System.IO;
namespace ConsoleApplication1
{
class Class1
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_MINIMIZE = 6;
private const int SW_MAXIMIZE = 3;
private const int SW_RESTORE = 9;
[STAThread]
static void Main(string[] args)
{
IntPtr winHandle =
System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
ShowWindow(winHandle, SW_MINIMIZE);
System.Threading.Thread.Sleep(2000);
ShowWindow(winHandle, SW_RESTORE);
}
}
}
If you're using Process.Start to start the console app, better use this:
System.Diagnostics.ProcessStartInfo process= new
System.Diagnostics.ProcessStartInfo(#"MyApplication.exe");
process.WindowStyle=System.Diagnostics.ProcessWindowStyle.Minimized;
process.UseShellExecute=false; // Optional
System.Diagnostics.Process.Start(process);
I don't know of a way to prevent the console window from ever displaying. The best approach in a console app is to hide the window, immediately after the app loads. The visual effect is a quick opening of a console window, then it disappears. Maybe not optimal.
A better approach might be to use a Winexe, instead of a console app. Inside the Windows app (maybe a winforms app), never instantiate the first form. Therefore nothing is ever displayed.
This prevents user interaction, but from your description, it sounds like that's what you want.
But I'm not sure you have control over the "console app".

Problem with Killing windows explorer?

I need to kill windows explorer's process (explorer.exe), for that
lets say i use a native NT method TerminateProcess
It works but the problem is that the explorer starts again, may be windows is doing that, anyway. When i kill explorer.exe with windows task manager, it doesn't come back, its stays killed.
I want to do whatever taskmanager is doing through my application.
Edit:
Thanks to #sblom i solved it, a quick tweak in the registry did the trick. Although its a clever hack, apparently taskmnager has a cleaner way of doing that, that said, i've decided to go with #sblom's way for now.
From Technet:
You can set the registry key HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoRestartShell to 0, and it will no longer auto-restart.
The "real" solution. (Complete program. Tested to work on Windows 7.)
using System;
using System.Runtime.InteropServices;
namespace ExplorerZap
{
class Program
{
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);
static void Main(string[] args)
{
int hwnd;
hwnd = FindWindow("Progman", null);
PostMessage(hwnd, /*WM_QUIT*/ 0x12, 0, 0);
return;
}
}
}
Here's another solution to this problem - instead api calls it uses an external tool shipped with windows (at least Win 7 Professional):
public static class Extensions
{
public static void ForceKill(this Process process)
{
using (Process killer = new Process())
{
killer.StartInfo.FileName = "taskkill";
killer.StartInfo.Arguments = string.Format("/f /PID {0}", process.Id);
killer.StartInfo.CreateNoWindow = true;
killer.StartInfo.UseShellExecute = false;
killer.Start();
killer.WaitForExit();
if (killer.ExitCode != 0)
{
throw new Win32Exception(killer.ExitCode);
}
}
}
}
I know that Win32Exception may not be the best Exception, but this method acts more or less like Kill - with the exception that it actually kills windows explorer.
I've added it as an extension method, so you can use it directly on Process object:
foreach (Process process in Process.GetProcessesByName("explorer"))
{
process.ForceKill();
}
You must first ensure that the taskkill tool is available on production environment (it seems that it's been for a while with windows: https://web.archive.org/web/20171016213040/http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/taskkill.mspx?mfr=true).
EDIT: Original link dead, replaced with cache from Internet Archive Wayback Machine. Updated documentation for Windows 2012/2016 can be found at: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/taskkill
What you probably need to do is instead of using TerminateProcess, post a WM_QUIT message to the explorer windows and main thread. It's a bit involved, but I found this page which has some example code that might help you along:
http://www.replicator.org/node/100
Windows will automatically restart explorer.exe after a TerminateProcess so that it restarts in the case of a crash termination.
I have some researches and these are reslts:
Windows will restart explorer after it closed -except by Task Manager-.
So you should change the related RegistryKey:
RegistryKey regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default).OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\Winlogon", RegistryKeyPermissionCheck.ReadWriteSubTree);
if (regKey.GetValue("AutoRestartShell").ToString() == "1")
regKey.SetValue("AutoRestartShell", 0, RegistryValueKind.DWord);
For changing a registry key the program should run as administrator:
You can show UAC prompt to user to run application as administrator as explaining in this Answer.
And if UAC is turned off I direct you to this Answer.
You can embed a manifest file in the exe, which will cause Windows Seven to always run the program as an administrator, As explaining in this Answer.
You should know you can't force your process starts as administrator; so you can run your process inside your process as another process! You can use this blog post or this answer.
You can also use reg command with this [Microsoft Windows Documentation].6.
After setting that -restarting explorer- off: This code can close explorer :
Process[] ps = Process.GetProcessesByName("explorer");
foreach (Process p in ps)
p.Kill();

Categories