Wpf and commandline app in the same executable
As @BrunoKlein suggested, I remove the StartupUri
property from App.xml
and then override the OnStartup
method. However I use AttachConsole
instead, as I found that AllocConsole
caused an extra console window to appear when run from command prompt.
It is also important to call FreeConsole
and Shutdown
to exit cleanly.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (e.Args.Length == 0)
{
// No command line arguments, so run as normal Windows application.
var mainWindow = new MainWindow();
mainWindow.ShowDialog();
}
else
{
// Command-line arguments were supplied, so run in console mode.
try
{
const int ATTACH_PARENT_PROCESS = -1;
if (AttachConsole(ATTACH_PARENT_PROCESS))
{
CommandLineVersionOfApp.ConsoleMain(e.Args);
}
}
finally
{
FreeConsole();
Shutdown();
}
}
}
[DllImport("kernel32")]
private static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32")]
private static extern bool FreeConsole();
}
You can check whether the application has been executed from a console. If not, you can allocate a console dynamically:
if (GetConsoleWindow() == IntPtr.Zero)
AllocConsole();
where
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll")]
public static extern bool AllocConsole();
@BrunoKlein's answer will work, and I based my answer on his solution. Quoting @BrunoKlein,
First you have to use a WPF Application project and change the app.xaml so that you can override the window creation.
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Application.Resources>
</Application.Resources>
</Application>
Note this is missing the StartupUri property.
Now, even simpler (this works in Visual Studio 2015 at least), go to the project properties, and change the output type from Windows Application to Console Application. This makes the project build as a console app, but still has the capabilities of a Windows Application.
(Class Library is highlighted in this photo, select Console Application instead)
You did it! Done.
Now, instead of having a void Main(string[] args)
, your "main" method is the OnStautup
method of your autogenerated App
class:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
string[] args = e.Args;
if (SomeConditionBasedOnTheArgs(args))
{
// Instantiate view, call View.Show()
}
else
{
// Process the args
}
}
}
Note the one difference between this answer and @BrunoKlein's answer is that this one will always "show" a console if it is run from explorer/start menu/desktop, but if run from the command line, it will run and direct all of its standard output to that console, just like any normal console application.
First you have to use a WPF Application project and change the app.xml
so that you can override the window creation.
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Application.Resources>
</Application.Resources>
</Application>
Note this is missing the StartupUri
property.
Then, on your App.xaml.cs
you can do something like this:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (condition)
{
var window = new MainWindow();
window.ShowDialog();
}
else
{
AllocConsole();
}
}
[DllImport("Kernel32.dll")]
static extern void AllocConsole();
}