Show/Hide the Console Window of a C# Console Application

Show/Hide the console window of a C# console application

Here’s how:

using System.Runtime.InteropServices;

[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;

var handle = GetConsoleWindow();

// Hide
ShowWindow(handle, SW_HIDE);

// Show
ShowWindow(handle, SW_SHOW);

Hide the console window from a console application

Go to the Application Properties and change Output Type from Console Application to Windows Application.

Or you can do it using a code below

using System.Runtime.InteropServices;
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

And in main

const int SW_HIDE = 0;
const int SW_SHOW = 5;
var handle = GetConsoleWindow();

ShowWindow(handle, SW_HIDE); // To hide
ShowWindow(handle, SW_SHOW); // To show

Also, you can run you application as a service. In order to do this you should create a service - File->New Project->Visual C#->Windows->Windows Service. Then create a public method StartWork() and add all you logic there. And call this method in OnStart().

 protected override void OnStart(string[] args)
{
try
{
this.StartJobs();
}
catch (Exception ex)
{
// catching exception
}
}

public void StartWork()
{
// all the logic here
}

In main you should create this service and use System.ServiceProcess.ServiceBase.Run() to run it as service or call StartWork() to run it as console application.

static void Main(string[] args)
{
TestService = new TestService ();

#if DEBUG
TestService.StartWork()();
#else
System.ServiceProcess.ServiceBase.Run(TestService );
#endif
}

Hide Console Window in C# Console Application

Change the output type from Console Application to Windows Application. This can be done under Project -> Properties -> Application in Visual Studio:

alt text

How to hide a console application in C#

Compile it as a Windows Forms application. Then it won't display any UI, if you do not explicitly open any Windows.

How to run a C# console application with the console hidden

If you are using the ProcessStartInfo class you can set the window style to hidden - in the case of console (not GUI) applications, you have to set CreateNoWindow to true:

System.Diagnostics.ProcessStartInfo start =
new System.Diagnostics.ProcessStartInfo();
start.FileName = dir + @"\Myprocesstostart.exe";
start.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; //Hides GUI
start.CreateNoWindow = true; //Hides console

Hiding the Console Window When Running Process as a User with DllImports

The only way of doing this I could find that actually worked is by running the commands via a remote PowerShell session as a user who has full domain access:

static class Ps
{
private const string RemoteHost = "ADMINSERVER.DOMAIN1.co.uk";
private static string _errors;

/// <summary>
/// Executes the given command over a remote powershell session
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static Collection<PSObject> RemoteCommand(string args)
{
SupportMi.Trace = $"Remote Command({args}) {{";

var script = BuildScript(args);
var results = Execute(script);

SupportMi.Trace = $"RES: {results[0]} ERR: {_errors} }}";
return results;
}

/// <summary>
/// Takes a complete script and executes it over a powershell Runspace. In this case it is being
/// sent to the server, and the results of the execution are checked for any errors.
/// </summary>
/// <param name="script"></param>
/// <returns></returns>
private static Collection<PSObject> Execute(string script)
{
var results = new Collection<PSObject>();

// Using a runspace
using (var runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();

using (var pipeline = runspace.CreatePipeline())
{
pipeline.Commands.AddScript(script);

try
{
results = pipeline.Invoke();
var errors = pipeline.Error.Read(pipeline.Error.Count);
foreach (var error in errors)
{
_errors += error;
}
}
catch (Exception ex)
{
results.Add(new PSObject(ex.Message));
SupportMi.Trace = ex.Message;
}
}
}

return results;
}

/// <summary>
/// Takes a string argument to be sent to the remote powershell session and arranges it in the correct format,
/// ready to be sent to the server.
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private static string BuildScript(string args)
{
// Build the script
var script = Creds() + Environment.NewLine +
$"Invoke-Command -session $sessions -ScriptBlock {{ {args} /U DOMAIN1\\adminusername /P adminpassword }}" + Environment.NewLine +
"Remove-PSSession -Session $sessions" + Environment.NewLine +
"exit";

return script;
}

/// <summary>
/// Returns the credentials for a remote PowerShell session in the form
/// of a few lines of PowerShell script.
/// </summary>
/// <returns></returns>
private static string Creds()
{
return "$pw = convertto-securestring -AsPlainText -Force -String \"adminpassword\"" + Environment.NewLine +
"$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist \"DOMAIN1\\adminusername\",$pw" + Environment.NewLine +
$"$sessions = New-PSSession -ComputerName {RemoteHost} -credential $cred";
}
}

So to maintain a console-less action we can call the RemoteCommand method and pass in the command we want to send. RemoteCommand will first build our query/command using BuildScript and Creds (for the admin credentials).

This is then sent to the Execute method, which creates a new PowerShell RunSpace, which can run the command.

Some caveats of using this method :

  • The app must be run on the domain on which the "admin" server exists
  • There must exist an admin account which has access to any machine which wishes to run this code as well as the server (in this case, ADMINSERVER)
  • Any errors will exist on the remote server, so we must take care to handle these properly so that they are passed back into our application


Related Topics



Leave a reply



Submit