【问题标题】:How to be dynamically either console application or Windows Application如何动态地成为控制台应用程序或 Windows 应用程序
【发布时间】:2015-07-08 22:47:43
【问题描述】:

我有一个应该在两种模式中执行的小应用程序:非 UI 或 WPF 窗口。它应该取决于命令行参数。

在每种模式下,我都需要显示一些反馈日志:

  1. 在 WPF 窗口模式下,WPF 将负责可视化日志,
  2. 在无 UI 模式下,我需要一个控制台来显示日志。如果我的应用程序是从控制台(主要是 cmd.exe)启动的,我想在不打开新应用程序的情况下使用它。如果我的应用是在控制台之外启动的(双击资源管理器、CreateProcess 等),我需要创建一个新控制台来输出结果并等待 Readkey 将其关闭。

我找到了:

而且我知道我可以在项目属性中静态选择“Windows 应用程序”或“控制台应用程序”。

选择“Windows 应用程序”,GetConsoleWindow() 始终为 0,我不知道如何重用以前的控制台。

选择“控制台应用程序”,我可以重复使用以前的控制台,但是当在 WPF 窗口模式下从资源管理器启动时,会在我的 WPF 主窗口下创建一个控制台。

问题是:应用程序如何才能真正动态? 在 WPF 窗口模式下,只有一个 WPF 窗口(根本没有控制台)或在非 UI 中,只有一个控制台(开始一个或一个新创建的)。

【问题讨论】:

  • 我认为它与 WPF 无关,而仅植根于 PE 标头和 main/winmain 中的子系统。

标签: c# .net


【解决方案1】:

在 Winforms 中要容易得多,但并不难。

从 WPF 应用程序项目开始(不是带有 WPF 窗口的控制台应用程序项目)。

在根目录下新建一个Program.cs类,添加如下代码:

class Program
{
    [DllImport("Kernel32")]
    public static extern void AllocConsole();

    [DllImport("Kernel32")]
    public static extern void FreeConsole();

    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(uint dwProcessId);

    [STAThread]
    public static void Main(string[] args)
    {
        bool madeConsole = false;
        if (args.Length > 0 && args[0] == "console")
        {

            if (!AttachToConsole())
            {
                AllocConsole();
                Console.WriteLine("Had to create a console");
                madeConsole = true;
            }

            Console.WriteLine("Now I'm a console app!");
            Console.WriteLine("Press any key to exit");
            Console.ReadKey(true);

            if (madeConsole)
                FreeConsole();
        }
        else
        {
            WpfApplication1.App.Main();
        }
    }


    public static bool AttachToConsole()
    {
        const uint ParentProcess = 0xFFFFFFFF;
        if (!AttachConsole(ParentProcess))
            return false;

        Console.Clear();
        Console.WriteLine("Attached to console!");
        return true;
    }

}

现在您有一个控制台应用程序或一个 WPF 应用程序。在属性中,将启动对象设置为Program.Main 方法。在上面的示例中,WpfApplication1.App.Main 是旧的启动对象(在 App.xaml.cs 文件中定义)。

编辑这错过了您对使用现有控制台的要求之一,一旦我弄清楚如何留在同一个控制台窗口中,我将立即对其进行编辑。

新编辑现在可以使用现有的控制台!

【讨论】:

  • 我已经尝试过这个解决方案。 您的情况是:“选择控制台应用程序”。我们可以重用以前的控制台,但是从资源管理器启动时,会在 WPF 主窗口下创建一个控制台。
  • @MuiBienCarlota 我建议您尝试我所做的,从 Windows 资源管理器启动时,您没有控制台窗口。发帖前我测试了很多次,没有出现任何窗口。您可能对项目类型感到困惑,这是 WPF 应用程序,而不是控制台应用程序,因此在创建项目时不要选择控制台应用程序。
  • 我在你的第一个代码上做了,我只是尝试你的最后一个代码。从 WPF 项目开始,使用新的 main 添加您的 Program 类,并将“启动对象”更改为您的 main 函数,并将输出类型更改为“控制台应用程序”。当我的程序从资源管理器启动时,我创建了一个控制台。
  • 我从来没有说过改变输出类型!将其保留为“Windows 应用程序”!
  • 是的,它适用于带有 ATTACH_PARENT_PROCESS 的 AttachConsole。谢谢。
猜你喜欢
  • 2012-03-07
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多