【发布时间】:2010-12-04 10:19:43
【问题描述】:
相关:
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,内核将进程的标准输入/标准输出设置为 NULL,如果非 GUI(命令行),内核创建一个控制台并将进程的标准输入/标准输出设置为安慰。
启动进程时,如果没有 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 应用程序有用。
这对我有用。
【问题讨论】:
-
您希望它做什么?
-
判断程序是否在自己的控制台中启动的测试是错误的。在命令行输入
cls & program.exe将错误地表明程序是在其自己的控制台中启动的。您可以从批处理文件中执行相同的操作。可能还有其他方法可以击败测试。
标签: .net windows console console-application