Running Silent

An embedded system sometimes needs to be able to execute a process without displaying a user interface. Have you ever seen a kiosk or other embedded Windows machine displaying DOS prompts on startup or when the UI crashes? We can hide these in .NET on Windows.

The approach depends on the type of project you are using: console application, Windows Forms, or WPF.

Console Applications

If you are using .NET Core, you will need to build a Windows specific executable, otherwise you just have a DLL file and later steps won’t work:

dotnet build ConsoleApp.csproj -c Debug -r win10-x64

The remainder of this applies to .NET Framework and .NET Core equally. You will need to install the C++ side of Visual Studio (Community edition sufficient). This will give you editbin.exe on a path such as this (your version may differ):

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64\editbin.exe

Reference the full path or use a Visual Studio command prompt. editbin is not placed on your PATH environment by default.

Now run this command against your console executable:

editbin.exe /subsystem:windows Program.exe

This command modifies the subsystem flag in the PE header of your executable. When you build a WPF app, the subsystem is set to windows. Altering a console app to windows mode prevents the console window from being drawn.

Amusingly, you can use the same utility to make a WinForm/WPF process also load a console window (use subsystem:console).

GUI Project Types

Why would you use a GUI project type and then want to hide it?

  • You are using another UI technology, such as Electron, backed by C# and you want to retain the ability to display a C# Window in some edge cases.
  • You have third party code that needs to be put on a window designer or needs a window handle to function, but otherwise your C# process does not need a UI. I’ve encountered signature pads and magnetic card swipes with this limitation.
  • Your own code needs to call native functions such as intercepting mouse and keyboard input. Generally this is easier to do within a UI thread and with a window handle available.

Windows Forms

Within Program.cs, simply do not pass a form instance to the Application.Run call like so:

        [STAThread]
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(); // No form given!
        }

If you need to construct a real form but not show it, leave your Program.cs as normal and override SetVisibleCore within the form code:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        protected override void SetVisibleCore(bool value)
        {
            base.SetVisibleCore(false);
        }
    }

You can now run the program but will see no UI. I suggest running with debugging attached.

WPF

A WPF project by default does not let you see the main method. It exists, but is part of generated code (App.g.cs within your obj folder). We have a few hoops to jump as a result.

Add a Program.cs class file to your project and give it this code:

        [STAThread]
        public static void Main(string[] args)
        {
            App app = new App();
            app.InitializeComponent();
            app.Run();
        }

Then in the project properties, Application section, change the Startup Object to your Program class. You now own the Main method control flow. Finally, in your MainWindow.xaml add the attribute Visibility="Hidden" to the Window tag.

Featured Image Credit

USS Virginia

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.