Creating Dual Use Windows GUI and Console Applications - Rick Strahl's Weblog
Contact •<br>Articles •<br>Products •<br>Support •
Sponsored by:
West Wind WebSurge
- Rest Client and Http Load Testing for Windows
advertise here
Rick Strahl
Rick's Sites
Rick's Products
Categories
Share on:
June 23, 2026<br>• from Hood River, Oregon
• 671 views
On this page:
In my last post I described a WebPackageViewer tool tool that acts as a static Web site packager and self-contained Web site viewer all contained in a single Executable.
One feature of this single file tool is that it acts both as a GUI application (the Web site viewer) and as a CLI application (the package/unpackage tooling) from a single EXE. However, using both GUI and CLI interface from a single EXE is challenging and doesn't have a 100% clean solution. In this post I'll describe several options that make this dual mode operation work with an as clean as possible approach, as well as some alternatives that I've used in other applications.
If you think this is an off the wall concept, all of my commercial desktop applications Markdown Monster, WebSurge and Documentation Monster have a support CLI for exposing common functionality in a scriptable way. But... in all of these latter cases I actually chose a different approach of using separate EXEs for the GUI app and CLI app with the CLI app driving the GUI app features. It's a very different use case than the simple single Exe WebPackager tool and it works well for full fledged applications that expose a CLI.
CLI Interfaces
In this post I'll discuss 3 different approaches. None of them are what I would consider perfect, which would be if Windows simply supported some way to cleanly service both GUI and Console apps from a single Exe.
But alas, it's Windows so we have to live with trade-offs. Here are the three I'll discuss:
Create a GUI application with a Console interface
Create a Console Application and launch GUI from Console
Create separate CLI and GUI applications with shared functionality
I've used all of these approaches now at some point or another, and it depends on the type of application or tool that you're building which makes the most sense.
GUI Application with CLI Interface Option
Mixed mode GUI app that also supports CLI output is the most tricky of these approaches, because Windows makes this sort of thing difficult with choose-one-or-the-other situation. It's also the most likely situation you're going to find yourself in when you build a GUI app and then later decide that it would be nice to add some CLI functionality.
When you build a Windows .NET application (or any Windows application for that matter) you havet to specify whether it's a WinExe (GUI) or Exe (Console) application. The type of app is written into the PE header when the EXE is created.
In .NET you can specify this in the project's header:
WinExe
net472<br>true<br>1.1.5.2
This affects the SubSystem value of the Windows PE header that gets generated into Windows Exes:
Figure 1 - GUI and Console apps have different startup semantics in how they related to Consoles that are attached or loaded based on the SubSystem value in the PE header.
When you launch as a Console application a new Console is started if none is active. That's when you invoke via the Windows shell or Explorer. If launched from an existing Console in the Terminal the Console app attaches to the existing Console and pipes output into it including all the Console streams (Input/Output/Error).
When you launch a GUI app from the shell, no Console is launched, so by default there's no Console - the Console points at a null console if you write to it and that output goes nowhere.
Where it gets weird is if you launch a GUI app from a Console, and you then write to the console which is the exact scenario that I'm using in WebPackageViewer .
By default the launching Console and the GUI exe are not connected and so by default Console input and output are still not going anywhere. However, it's possible to attach to an existing Console using a native AttachConsole() call from a GUI application when the application starts up, which effectively allows your GUI application to send Console output and input to and from the console.
You can use the following two P/Invoke calls (on Windows) to attach and release the Console:
[DllImport("kernel32.dll", SetLastError = true)]<br>static extern bool FreeConsole();
[DllImport("kernel32.dll", SetLastError = true)]<br>static extern bool AttachConsole(int dwProcessId);
Then as part of your application's startup code you can attach the Console:
protected override void OnStartup(StartupEventArgs e)<br>bool attached = AttachConsole(-1); // -1 - active console<br>...
if (attached)<br>Console.Write("\n✅ Launching Web Viewer...");
...
// when done<br>if(attached)<br>FreeConsole();
This sorta works.
The problem is that Console output goes into the active console that the application was started from, but if the...