Related:
Should I include a command line mode in my applications?
How to grab parent process standard output?
Can a console application detect if it has been run from Explorer?
我想构建一个通常从命令行运行的控制台应用程序。
但是,当它在资源管理器中双击时(而不是在 cmd.exe 提示符下运行),我希望程序不显示控制台窗口。
我想避免这种情况:
这可能吗?
编辑 我想另一种提问方式是,程序是否有可能知道它是如何被调用的——无论是通过双击还是通过命令行?
我在 Windows 上使用 .NET 工作。
编辑 2: 来自 this Old New Thing blog post我学到了一些好东西。这是我现在所知道的...
在 Windows 中,EXE 文件被标记为 GUI 或非 GUI。对于 csc.exe,这是通过 /target:winexe
或 /target:exe
选择的。在进程中的第一条指令执行之前,Windows 内核会设置执行环境。在那一刻,如果 EXE 被标记为 GUI,内核将进程的 stdin/stdout 设置为 NULL,如果非 GUI(命令行),内核将创建一个控制台并将进程的 stdin/stdout 设置为安慰。
启动进程时,如果没有stdin/stdout (== /target:winexe
),则调用立即返回。因此,从 cmd.exe 启动 gui 应用程序,您将立即返回 cmd 提示符。如果有标准输入/标准输出,并且如果从 cmd.exe 运行,则父 cmd.exe 等待进程退出。
“立即返回”很重要,因为如果您编写一个 GUI 应用程序以附加到其父控制台,您将能够执行 console.writeline 等操作。但是 cmd.exe 提示符是事件的。用户可以键入新命令、启动新进程等。换句话说,从 winexe 中,简单地使用 AttachConsole(-1)
附加到父控制台不会将其“变成”控制台应用程序。
在这一点上,我认为允许应用程序在从 cmd.exe 调用时使用控制台,并且在双击时不使用它的唯一方法是将 exe 定义为常规控制台 exe ( /target:exe
),并在启动时隐藏窗口(如果合适)。您仍然会看到一个控制台窗口短暂出现。
我仍然没有想出如何知道它是从资源管理器还是从 cmd.exe 启动的,但我越来越接近了..
答案
无法构建不显示控制台窗口的控制台应用程序。
有可能构建一个非常快速地隐藏其窗口的控制台应用程序,但不能快到窗口好像永远不会出现一样。
现在,要确定控制台应用程序是否是从资源管理器启动的,有些人建议查看它在其中运行的控制台
(来自 mgb's answer 和 KB article 99115 ):
int left = Console.CursorLeft;
int top = Console.CursorTop;
bool ProcessWasRunFromExplorer = (left==0 && top==0);
这会告诉您进程是否在其自己的控制台中启动,但不会告诉您它是否是资源管理器。在资源管理器中双击会执行此操作,但应用程序中的 Start.Process() 也会执行相同的操作。
如果您想区别对待这些情况,请使用它来了解父进程的名称:
System.Console.WriteLine("Process id: {0}", Process.GetCurrentProcess().Id);
string name = Process.GetCurrentProcess().ProcessName ;
System.Console.WriteLine("Process name: {0}", name);
PerformanceCounter pc = new PerformanceCounter("Process", "Creating Process Id", name);
Process p = Process.GetProcessById((int)pc.RawValue);
System.Console.WriteLine("Parent Process id: {0}", p.Id);
System.Console.WriteLine("Parent Process name: {0}", p.ProcessName);
// p.ProcessName == "cmd" or "Explorer" etc
要在进程启动后快速隐藏窗口,请使用:
private static readonly int SW_HIDE= 0;
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
....
{
IntPtr myHandle = Process.GetCurrentProcess().MainWindowHandle;
ShowWindow(myHandle, SW_HIDE);
}
如果您生成一个 winexe
(一个 WinForms 应用程序),并在适当的时候使用 AttachConsole(-1)
选择性地附加到父控制台,您不会得到等效的一个常规的控制台应用程序。对于 winexe,父进程(如 cmd.exe)将在启动 GUI 应用程序后立即返回到命令提示符。换句话说,命令提示符处于事件状态并准备好输入,而刚刚启动的进程可能正在发出输出。这令人困惑,可能仅对调试 winforms 应用程序有用。
这对我有用。
最佳答案
只需将其构建为 Windows 窗体应用程序,但不要为其提供 GUI。不幸的是,当它从命令行运行时,您也不会得到任何控制台输出……这是个问题吗?
关于.net - 是否可以构建双击时不显示控制台窗口的控制台应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1528152/