相关:
我应该在我的应用程序中包含命令行模式吗?
如何抓取父进程标准输出?
控制台应用程序是否可以检测它是否已从资源管理器运行?
我想构建一个控制台应用程序,通常从命令行运行。
但是,当从资源管理器中双击它(而不是从 cmd.exe 提示符运行)时,我希望程序不显示控制台窗口。
我想避免这种情况:
是否可以?
编辑我想另一种方法是,程序是否有可能知道它是如何被调用的——无论是通过双击还是通过命令行?
我在 Windows 上的 .NET 中工作。
编辑 2:从这篇Old New Thing博客文章中,我学到了一些好东西。以下是我现在所知道的...
在 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 的回答和知识库文章 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 应用程序有用。
这对我有用。