C# Wpf和命令行应用程序位于同一可执行文件中
我希望有一个可执行文件,可以用来打开图形应用程序(单击.exe时为默认用例),也可以用来运行命令行任务 这可能吗C# Wpf和命令行应用程序位于同一可执行文件中,c#,wpf,command-line,C#,Wpf,Command Line,我希望有一个可执行文件,可以用来打开图形应用程序(单击.exe时为默认用例),也可以用来运行命令行任务 这可能吗 如果是,我将如何修改我的app.xaml/app.xaml.cs,使其仅打开特定条件下的图形视图(例如,无命令行参数) 首先,您必须使用WPF应用程序项目并更改app.xml,以便覆盖窗口创建 <Application x:Class="WpfApplication1.App" xmlns="http://schemas.microsoft.com/w
如果是,我将如何修改我的app.xaml/app.xaml.cs,使其仅打开特定条件下的图形视图(例如,无命令行参数) 首先,您必须使用WPF应用程序项目并更改
app.xml
,以便覆盖窗口创建
<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>
您可以检查应用程序是否已从控制台执行。如果没有,您可以动态分配控制台:
if (GetConsoleWindow() == IntPtr.Zero)
AllocConsole();
在哪里
@BrunoKlein的答案会起作用,我的答案基于他的解决方案。引用@BrunoKlein
首先,您必须使用WPF应用程序项目并更改app.xaml,以便覆盖窗口创建
<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>
请注意,此答案与@BrunoKlein的答案之间的一个区别是,如果从资源管理器/开始菜单/桌面运行,此答案将始终“显示”控制台,但如果从命令行运行,它将运行并将其所有标准输出定向到该控制台,就像任何普通的控制台应用程序一样。在使用上述两种解决方案时,我总是遇到一个bug。本文对此进行了描述,并以相同的方式进行了解决。 工具→ 选择权→ 调试→ 一般的→ 选中“使用托管兼容性模式” 继续搜索不需要关闭某些调试选项的解决方案,我发现这篇文章对我来说非常有用。 如果它被删除,请添加一个Program.cs,将Windows应用程序交换到控制台应用程序,并使App.Program成为启动对象。然后在Program.cs中,添加并调整以下代码。DLL导入负责隐藏控制台窗口。 所有的功劳都归@Benohead 我将默认设置更改为GUI模式,并使参数触发控制台应用程序。 控制台窗口将在进入GUI模式之前显示并关闭
using System;
using System.Runtime.InteropServices;
namespace HybridApp
{
public class Program
{
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[STAThread]
public static void Main(string[] args)
{
if (args.Length == 0)
{
// GUI mode
ShowWindow(GetConsoleWindow(), 0 /*SW_HIDE*/);
App.Main();
}
else if (args.Length > 0 && args[0] == "-c")
{
// console mode
Console.WriteLine("Console mode active!");
Console.ReadLine();
}
}
}
}
正如@BrunoKlein所建议的,我从
App.xml
中删除StartupUri
属性,然后覆盖OnStartup
方法。但是我使用了AttachConsole
,因为我发现alloconsole
在从命令提示符运行时会出现一个额外的控制台窗口
调用FreeConsole
和Shutdown
以干净地退出也很重要
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();
}
您可以传递一个标志来指示命令行模式,如果存在,请使用AttachConsole将您的应用程序附加到启动它的控制台。请参阅和示例,如果该应用程序已从控制台启动,但未获取任何命令行参数,我仍希望打开该窗口……只需这样做即可。:)您必须先检查命令行参数,然后再检查。无论如何,在分配控制台之前,您可能需要检查应用程序是否已经有了控制台。
AttachConsole
可能比allocsole
更好。有关详细信息,请参阅我的答案。
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
}
}
}
using System;
using System.Runtime.InteropServices;
namespace HybridApp
{
public class Program
{
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[STAThread]
public static void Main(string[] args)
{
if (args.Length == 0)
{
// GUI mode
ShowWindow(GetConsoleWindow(), 0 /*SW_HIDE*/);
App.Main();
}
else if (args.Length > 0 && args[0] == "-c")
{
// console mode
Console.WriteLine("Console mode active!");
Console.ReadLine();
}
}
}
}
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();
}