一个可从控制台运行但不会创建窗口的C#应用程序

3
我希望创建一个 C# 应用程序,当从控制台窗口运行应用程序并可以在控制台输出文本时,它的行为就像控制台应用程序一样。但是当从外部运行时,不会创建控制台窗口。我已经做了一些研究,通常建议是创建一个 C# 控制台应用程序,然后将其项目类型更改为 Windows 应用程序。但是,这样做会阻止 Console.WriteLine 信息在从控制台运行时被写入。
有没有办法以这种方式运行程序?我不需要它接收任何控制台输入。也许有其他方法可以用来在从控制台运行时显示文本?

这是你需要的东西吗:https://dev59.com/yWox5IYBdhLWcg3wvWoy - rene
使用AttachConsole并使用ATTACH_PARENT_PROCESS来附加运行的控制台,从而避免在控制台中运行时写入Console.WriteLine消息。 - Idle_Mind
@Idle_Mind 这是个好的开始;我可以在控制台窗口看到输出结果,但即使调用了FreeConsole()方法,它仍不会退出控制台提示符。 - RandomEngy
不太确定我理解了...你能给更多细节吗? - Idle_Mind
@Idle_Mind 噢,它确实存在,只是它立即执行,所以所有控制台输出在提示符后奇怪地显示出来:http://i.imgur.com/OHQOchH.png - RandomEngy
明白了...没错。这是一个Windows应用程序的正常行为(您更改了输出类型),因为它们不会阻止控制台。对于这个问题,我没有一个好的答案,抱歉。 - Idle_Mind
3个回答

3
所有的控制台输出在提示符后面都会出现问题。
使用AttachConsole()实际上效果不佳。命令处理器会查看你的.exe文件并根据其是控制台模式应用程序还是GUI应用程序执行两种不同的操作。如果它是控制台模式应用程序,则等待程序退出,然后显示提示符。如果是GUI应用程序,则不等待,并假设程序将显示自己的窗口。
这就发生了,它在启动您的程序后显示提示符并等待输入。此时,您的Console.Write()输出将与命令处理器输出混合。您还将遇到Console.ReadLine()的问题,用户输入的第一行将进入命令处理器,而不是进入您的程序中,使用户非常困惑。
解决方法是以不同的方式启动您的程序。您需要键入:
  start /wait yourapp.exe args...

这使命令处理器等待您的程序退出,就像等待控制台模式应用程序一样。这并不是很实用,您的应用程序用户不会想到使用“start /wait”。没有简单的解决方法,您需要使用AllocConsole()。如果这是一个让人无法接受的问题,那么您只需要创建另一个小的EXE项目,它是一个控制台应用程序。它启动您的GUI应用程序,传递命令行。如果您给它与GUI exe相同的名称但给出“.com”文件名扩展名,则它将始终被找到。它可以看起来像这样,适用于任何GUI应用程序:
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

class Program {
    static void Main(string[] args) {
        try {
            var path = Assembly.GetExecutingAssembly().Location;
            var dir = Path.GetDirectoryName(path);
            var file = Path.GetFileNameWithoutExtension(path);
            path = Path.Combine(dir, file + ".exe");

            var prc = Process.Start(path, Environment.CommandLine);
            if (args.Length > 0) prc.WaitForExit();
        }
        catch (Exception ex) {
            Console.WriteLine(ex.Message);
            Environment.Exit(1);
        }
    }
}

那差不多了;我还需要转发参数和标准输出。虽然对于我的目的,我想我会将CLI作为控制台应用程序保留,并创建一个小包装器Windows应用程序,它传递参数并隐藏控制台窗口。当我需要在没有窗口的情况下启动时,我可以使用它,而CLI项目仍将正常工作。不过,使用.com扩展名是个有用的技巧。 - RandomEngy

0
说实话,我也需要这个,并且一直在寻找答案,最终在Windows应用程序中显示控制台?中找到了。
public static void ShowConsoleWindow()
{
    var handle = GetConsoleWindow();

    if (handle == IntPtr.Zero)
    {
        AllocConsole();
    }
    else
    {
        ShowWindow(handle, SW_SHOW);
    }
}

public static void HideConsoleWindow()
{
    var handle = GetConsoleWindow();

    ShowWindow(handle, SW_HIDE);
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

const int SW_HIDE = 0;
const int SW_SHOW = 5;

这看起来是一个很好的解决方案,能够解决本贴中其他人所提出的所有问题。


我不想从Windows应用程序创建一个新的控制台。我想在控制台中正常运行它,并且在命令提示符之外启动时没有窗口。 - RandomEngy
我明白了,很抱歉,我对此没有答案。我甚至不知道该如何开始。 - user2888973

0

供参考,这是我所做的。我创建了一个简单的“无窗口CLI”可执行文件。我创建了一个新的控制台应用程序,将其更改为Windows应用程序并传递了参数:

static void Main(string[] args)
{
    string programFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    string passArguments = string.Join(" ", args.Select(WrapArgument));

    Process.Start(new ProcessStartInfo(Path.Combine(programFolder, "VidCoderCLI.exe"))
    {
        Arguments = passArguments,
        WindowStyle = ProcessWindowStyle.Hidden
    });
}

private static string WrapArgument(string arg)
{
    if (arg.EndsWith(@"\"))
    {
        return "\"" + arg + "\\\"";
    }

    return "\"" + arg + "\"";
}

任何需要进行调用而不显示窗口的内容都会通过这里进行处理。这很好,因为我避免了处理输出重定向和控制台问题。

虽然这不是我所要求的技术性答案,所以我不会接受这个答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接