相关信息: 我应该在我的应用程序中包括命令行模式吗? 如何获取父进程标准输出? 控制台应用程序是否已从资源管理器中运行?
我想要构建一个控制台应用程序,这通常是从命令行运行。
但是,当在资源管理器中双击它(而不是从cmd.exe提示符中运行)时,我希望程序不显示控制台窗口。
我想避免这样做:

有可能吗?
编辑--我想另一种问它的方法是,程序是否可能知道它是如何被调用的--无论是通过双击还是通过命令行?
我在.NET工作,在Windows上。
编辑2:从博客帖子学到了一些好东西。我现在知道的是..。
在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提示。如果存在stdin/stdout,如果从cmd.exe运行,则父cmd.exe等待进程退出。
“立即返回”很重要,因为如果您编写了一个GUI应用程序来附加到它的父控制台,您将能够执行console.writeline等操作。但是cmd.exe提示符是活动的。用户可以键入新命令,启动新进程,等等。换句话说,通过winexe,简单地使用AttachConsole(-1)附加到父控制台不会“将其转换为”控制台应用程序。
在这一点上,我认为允许应用程序在从cmd.exe调用控制台时使用控制台的唯一方法,而不是在双击时使用它的唯一方法是将exe定义为常规控制台exe (/target:exe),并在启动时酌情隐藏窗口。您仍然会看到一个控制台窗口出现的时间很短。
我仍然不知道如何知道它是从探险家还是从cmd.exe发射的,但我离它越来越近了。
应答
不可能构建不显示控制台窗口的控制台应用程序。
这是可能的建立一个控制台应用程序隐藏它的窗口非常快,但不那么快,它就好像窗口从来没有出现。
现在,为了确定控制台应用程序是否是从资源管理器启动的,一些人建议查看它正在运行的控制台。
(来自mgb的回答和KB第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应用程序有用。
这对我有用。
发布于 2009-10-06 21:45:34
请参阅Win32控制台应用程序能否检测它是否已从资源管理器运行?
或者我认为正式的方法是检查父进程是cmd.exe或explorer.exe。
发布于 2009-10-06 21:21:32
只需将其构建为Windows窗体应用程序,但不要为其提供GUI。不幸的是,当从命令行运行时,您将无法获得任何控制台输出.这有问题吗?
发布于 2009-10-06 21:48:06
因此,我已经用GUI和CLI编写了工具。最困难的部分是找出要打开哪一个--但是在我们的例子中,CLI版本需要参数,所以如果没有任何参数,我就打开GUI。然后,如果他们想要一个控制台,就调用一个类似于以下内容的函数:
private const int ATTACH_PARENT_PROCESS = -1;
private const int ERROR_INVALID_HANDLE = 6;
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll")]
static extern bool AllocConsole();
[DllImport("kernel32.dll")]
static extern bool FreeConsole();
private static bool StartConsole()
{
if (!AttachConsole(ATTACH_PARENT_PROCESS)) // try connecting to an existing console
{
if (Marshal.GetLastWin32Error() == ERROR_INVALID_HANDLE) // we don't have a console yet
{
if (!AllocConsole()) // couldn't create a new console, either
return false;
}
else
return false; // some other error
}
return true;
}返回是否创建了控制台。完成后不要忘了使用FreeConsole()!
当然,在我们的例子中,如果我们不创建一个控制台,我们就创建一个GUI。不过,创建控制台或不使用UI也同样容易。
编辑:当然,当我开始写这篇文章时,这完全没有回答编辑中的问题。除此之外,我们的黑客只是检查是否用命令行参数调用它。
https://stackoverflow.com/questions/1528152
复制相似问题