如何隐藏控制台运行C#控制台应用程序

160

有没有一种方法可以在执行控制台应用程序时隐藏控制台窗口?

我目前正在使用 Windows Forms 应用程序启动控制台进程,但我不希望在任务运行时显示控制台窗口。


尝试从计划任务中运行控制台应用程序。 - user2822353
这回答您的问题吗?显示/隐藏C#控制台应用程序的控制台窗口 - StayOnTarget
13个回答

230

如果您编写了控制台应用程序,则可以默认将其隐藏。

创建一个新的控制台应用程序,然后将“输出类型”更改为“Windows应用程序”(在项目属性中完成)。


9
我试图隐藏自己的控制台,而不是调用其他东西然后隐藏它(就像接受答案所假设的那样),所以这对我来说是最好的选择。谢谢! - iamserious
4
接受的答案认为这是因为它在问题中被声明了。 - aqua
1
这个方法解决了ProcessStartInfo的问题,当你指定用户凭据并且该用户已登录或是当前用户时。在这种情况下,CreateNoWindow属性会被忽略,因此你总是会得到一个控制台窗口。通过将控制台应用程序设置为Windows应用程序但没有窗口,你就不会得到窗口。 - tjmoore
注意,在VS 2017中,它被标记为应用程序类型下的Windows窗体应用程序。 - Gabe
这样的解决方案真的让人不明白微软当初在想什么...一点也不直观... - Asheq Reza
显示剩余2条评论

172
如果您使用的是ProcessStartInfo类,则可以将窗口样式设置为隐藏 - 对于控制台(非GUI)应用程序,您必须将CreateNoWindow设置为true
System.Diagnostics.ProcessStartInfo start =
      new System.Diagnostics.ProcessStartInfo();
start.FileName = dir + @"\Myprocesstostart.exe";
start.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; //Hides GUI
start.CreateNoWindow = true; //Hides console

27
刚好我想发表的内容 :) - Jon Skeet
81
天啊,有人跑得比Jon还快!=) - Erik Forbes
80
我不得不限制他的网络速度才能打败他 ;) - Adam Markowitz
11
无法使用调用命令行工具的方法。改用yourprocess.StartInfo.CreateNoWindow=true;,请参见以下内容。 - Christian
12
如果不想隐藏控制台窗口,需要设置StartInfo.CreateNoWindow = true。 - Daniel B
显示剩余2条评论

69
如果您正在使用Process类,那么您可以编写以下代码:
yourprocess.StartInfo.UseShellExecute = false;
yourprocess.StartInfo.CreateNoWindow = true;

yourprocess.start(); 之前,进程将被隐藏


4
如果你必须提前停止那个进程,祝你好运。Process.Kill 会突然终止进程,Process.CloseMainWindow 失败,GenerateConsoleCtrlEvent 发送 ctrl+c 或者 ctrl+break 到进程失败,向进程的所有线程窗口发送 WM_CLOSE 也会失败。似乎没有办法干净地结束使用这两个参数值启动的进程。请参考我的这个问题:https://dev59.com/e2Qo5IYBdhLWcg3wVuGP - Triynko
非常感谢,这是最简单的方法。如果您拥有(或负责)控制台代码,我发现这个互斥量示例最容易实现干净的关闭。https://dev59.com/e2Qo5IYBdhLWcg3wVuGP#31586184 - cbuteau
2
@Triynko:除非该进程积极合作,否则您无法干净地终止任何进程。这不是标志或其他任何事情的问题。操作系统中没有任何东西可以触发清洁关闭。常见的解决方案是使用可等待内核对象,在控制进程中发出信号,当从属进程应该终止时。从属进程需要积极监视此可等待对象的状态,并在其被信号触发后启动干净关闭。 - IInspectable
子进程也可以使用父进程作为关闭信号(如果子进程不应该比父进程长寿)。传入父进程PID,使用Process.GetProcessById(pid).WaitForExit(...)来等待或轮询。只有一个选项。 - undefined

49

简单的回答是:进入您的控制台应用程序属性(项目属性)。在“应用程序”选项卡中,只需将“输出类型”更改为“Windows应用程序”。就这样。


5
靶心。这与创建不调用任何窗体的Windows应用程序相同。 - ashes999
2
这就是正确答案,没有其他的权宜之计。这才是真正的正确答案。你希望你的应用程序根本不会先打开控制台。此外,你希望随时能够打开一个窗体。因此,你只需要在需要的时候调用窗体。例如,当用户右键单击系统托盘图标并选择“首选项”时,我们的表单就会被调用。 这才是正确答案! - Bluebaron

22

你可以使用FreeConsole API来将控制台从进程中分离:

[DllImport("kernel32.dll")]
static extern bool FreeConsole();

(当然,前提是您可以访问控制台应用程序的源代码)


我想不显示控制台。虽然FreeConsole做了它的名字所说的,但它不能防止Windows在调用它之前显示控制台。 - Jader Dias
5
将该项目编译为Windows应用程序,而不是控制台应用程序。 - Thomas Levesque
1
记录一下,这正是我所需要的,谢谢。它也恰好符合标题所要求的 :) 所以为了其他谷歌航行者的利益,+1。 - sehe
4
此外,[DllImport("kernel32.dll")] static extern bool AllocConsole(); 允许您从标准的Win32应用程序中轻松地运行并搭配使用控制台。 - sehe
1
适用于我的.NET Core 2.2应用程序 - 如果有人特别寻找这个。 - Medismal

7
如果您对输出感兴趣,可以使用此函数:
private static string ExecCommand(string filename, string arguments)
{
    Process process = new Process();
    ProcessStartInfo psi = new ProcessStartInfo(filename);
    psi.Arguments = arguments;
    psi.CreateNoWindow = true;
    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.UseShellExecute = false;
    process.StartInfo = psi;

    StringBuilder output = new StringBuilder();
    process.OutputDataReceived += (sender, e) => { output.AppendLine(e.Data); };
    process.ErrorDataReceived += (sender, e) => { output.AppendLine(e.Data); };

    // run the process
    process.Start();

    // start reading output to events
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();

    // wait for process to exit
    process.WaitForExit();

    if (process.ExitCode != 0)
        throw new Exception("Command " + psi.FileName + " returned exit code " + process.ExitCode);

    return output.ToString();
}

它运行给定的命令行程序,等待其完成并将输出作为字符串返回。

4

如果您正在创建一个不需要用户输入的程序,您可以将其创建为服务。服务不会显示任何类型的用户界面。


但是,如果你只想运行进程直到它退出,例如通过从任务计划程序调用它,那么服务是不方便的,因为它会继续存在。在某些情况下,将输出类型更改为Windows应用程序而不是隐藏的替代ProcessWindowStyle非常方便。 - subsci

3
将以下代码添加到您的类中以导入DLL文件:

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

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

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

如果您想隐藏它,请使用以下命令:

 var handle = GetConsoleWindow();
 ShowWindow(handle, SW_HIDE);

如果你想显示控制台:

var handle = GetConsoleWindow();
ShowWindow(handle, SW_SHOW);

1
[DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow(); const int SW_HIDE = 0; const int SW_SHOW = 5; - soulmachine

2
我有一个通用解决方案要分享:
using System;
using System.Runtime.InteropServices;

namespace WhateverNamepaceYouAreUsing
{
    class Magician
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

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

        const int HIDE = 0;
        const int SHOW = 5;

        public static void DisappearConsole()
        {
            ShowWindow(GetConsoleWindow(), HIDE);
        }
    }
}

只需将这个类包含在您的项目中,然后调用Magician.DisappearConsole();
当您点击并开始程序时,控制台会闪烁。从命令提示符执行时,命令提示符会在执行后很短时间内消失。
我在为我的 Discord Bot 运行时使用此方法,该机器人作为计算机后台的不可见进程运行。这比使 TopShelf 对我工作更容易。在编写此代码之前,我尝试了一些 TopShelf 教程,但失败了,并从其他地方找到了一些帮助。 :P
我还尝试了在 Visual Studio > 项目 > 属性 > 应用程序中简单更改设置,将其启动为 Windows 应用程序而不是控制台应用程序,但由于DSharpPlus需要在启动时启动控制台,因此我的项目某些设置防止了这样做。我不知道是什么原因,但无论出于何种原因,此类允许我轻松地在弹出后终止控制台。
希望这个“魔术师”能对某些人有所帮助。;)

1

根据Adam Markowitz上面的回答,以下方法适用于我:

process = new Process();
process.StartInfo = new ProcessStartInfo("cmd.exe", "/k \"" + CmdFilePath + "\"");
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
//process.StartInfo.UseShellExecute = false;
//process.StartInfo.CreateNoWindow = true;
process.Start();

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