Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Wpf和命令行应用程序位于同一可执行文件中_C#_Wpf_Command Line - Fatal编程技术网

C# Wpf和命令行应用程序位于同一可执行文件中

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

我希望有一个可执行文件,可以用来打开图形应用程序(单击.exe时为默认用例),也可以用来运行命令行任务

这可能吗


如果是,我将如何修改我的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();
}