相关:我应该在我的应用程序中包含命令行模式吗?如何获取父进程标准输出?控制台应用程序可以检测它是否已从资源管理器运行?
我想构建一个控制台应用程序,通常从命令行运行 .
但是,当它从资源管理器中双击(而不是从cmd.exe提示符运行)时,我希望该程序不显示控制台窗口 .
我想避免这个:
alt text http://i36.tinypic.com/1088p5s.jpg
可能吗?
EDIT 我想另一种问题是,程序是否有可能知道它是如何被调用的 - 无论是通过双击还是通过命令行?
我在Windows上使用.NET .
EDIT 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提示符 . 如果存在stdin / stdout,并且从cmd.exe运行,则父cmd.exe将等待进程退出 .
"immediate return"很重要,因为如果您编写GUI应用程序以附加到其父级控制台,您将能够执行console.writeline等 . 但cmd.exe提示符处于活动状态 . 用户可以键入新命令,启动新进程等 . 换句话说,从winexe,只需使用 AttachConsole(-1)
附加到父控制台,就不会"turn it into"一个控制台应用程序 .
此时我认为允许应用程序使用控制台的唯一方法是从cmd.exe调用它,如果双击则不使用它,就是将exe定义为常规控制台exe( /target:exe
),如果合适,在启动时隐藏窗口 . 您仍然会暂时显示控制台窗口 .
我仍然没有想过如何知道它是从explorer或cmd.exe启动的,但我越来越近了..
ANSWERS
无法构建不显示控制台窗口的控制台应用程序 .
可以构建一个控制台应用程序,可以非常快速地隐藏其窗口,但不会太快,以至于窗口永远不会出现 .
现在,要确定是否从资源管理器启动了控制台应用程序,有些人建议查看它正在运行的控制台
(来自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应用程序 .
这对我有用 .
5 回答
见Can a Win32 console application detect if it has been run from the explorer or not?
或者我认为官方的方法是检查父进程是cmd.exe还是explorer.exe
所以,我用GUI和CLI编写了工具 . 困难的部分是确定要打开哪一个 - 但在我们的例子中,CLI版本需要参数,所以我只是在没有任何参数的情况下打开GUI . 然后,如果他们确实想要一个控制台,请调用一个看起来像这样的函数:
返回是否已创建控制台 . 完成后别忘了FreeConsole()!
在我们的例子中,当然,如果我们不尽可能地创建控制台或没有UI .
编辑:当然,当我开始编写时,完全没有回答编辑中的问题 . 除此之外我们hack只是检查是否使用命令行参数调用它 .
只需将其构建为Windows窗体应用程序,但不要为其提供GUI . 不幸的是,当你从命令行运行时,你不会获得任何控制台输出......这是一个问题吗?
我没有读过所有内容,但是这样做了(不久前,需要更多测试):
IFF附加了多个proc,我需要恢复我操作的控制台,否则不行 . 可能有用,至少它本身就很简单 . 从VS启动代码将产生一个附加的进程,从commandprompt运行它确实激活了分支来清理我的混乱 . 顺便说一句,从资源管理器或其他非控制台应用程序启动的控制台将具有零长度 Headers ?
这会更像是服务吗?
要么
那些没有可见表单的Windows窗体应用程序怎么样?它仍会显示在“任务管理器进程”列表中 .