是否有可能build立一个控制台应用程序,双击时不显示控制台窗口?

有关:
我应该在我的应用程序中包含命令行模式吗?
如何抓取父进程的标准输出?
控制台应用程序可以检测到它是否已经从资源pipe理器运行?

我想构build一个控制台应用程序,通常从命令行运行。

但是,当它从资源pipe理器中双击(而不是从cmd.exe提示符运行),那么我想程序不显示控制台窗口。

我想避免这个:

替代文字http://img.zgserver.com/windows/1088p5s.png

可能吗?

编辑我猜想另一种方法来问它是否有可能让程序知道它是如何被调用的 – 无论是通过双击或通过命令行

我在.NET上工作,在Windows上。

编辑2:从这个旧的新事博客文章,我学到了一些好东西。 这是我现在知道的…

在Windows中,EXE文件被标记为GUI或非GUI。 使用csc.exe,通过/target:winexe/target:exe 。 在执行过程中的第一条指令之前,Windows内核将设置执行环境。 此时,如果EXE被标记为GUI,则内核将进程的stdin / stdout设置为NULL,如果非GUI(命令行)内核创build控制台并将进程的stdin / stdout设置为安慰。

启动进程时,如果没有标准input/标准输出(== /target:winexe ),则立即返callback用。 所以,从cmd.exe启动一个GUI应用程序,你会立即得到你的cmd提示符。 如果存在stdin / stdout,并且从cmd.exe运行,则父级cmd.exe将等待进程退出。

“立即返回”是非常重要的,因为如果你编写一个GUI应用程序来连接到它的父级控制台,你将能够执行console.writeline等,但是cmd.exe提示符是活动的。 用户可以键入新的命令,开始一个新的过程,等等。 换句话说,从winexe中,只需使用AttachConsole(-1)连接到父控制台就不会将其“变成”控制台应用程序。


此时我认为允许应用程序使用控制台(如果从cmd.exe调用的话),而不是在双击时使用它的唯一方法是将exe定义为常规控制台exe( /target:exe ),并在适当的时候启动窗口 。 您仍然可以看到简要的控制台窗口。

我还没有想到如何知道它是从资源pipe理器或cmd.exe启动,但我越来越接近..


解答

无法构build不显示控制台窗口的控制台应用程序。

有可能构build一个控制台应用程序,很快就隐藏窗口,但不能太快,以至于窗口永远不会出现。

现在,要确定一个控制台应用程序是否从资源pipe理器启动,有人build议查看它正在运行的控制台
(从mgb的答案 , 知识库文章99115 ):

  int left = Console.CursorLeft; int top = Console.CursorTop; bool ProcessWasRunFromExplorer = (left==0 && top==0); 

这告诉你,如果进程在自己的控制台启动,而不是它是否是资源pipe理器。 在资源pipe理器中双击会做到这一点,而且一个应用程序内的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应用程序),并且可以select使用AttachConsole(-1)附加到父控制台,则不会获得常规控制台应用程序的等效function。 对于winexe,父进程(如cmd.exe)将在启动GUI应用程序后立即返回到命令提示符。 换句话说,命令提示符处于活动状态并且准备好input,而刚刚启动的进程可能正在发送输出。 这是令人困惑的,可能仅用于debuggingwinforms应用程序。

这对我有效。

Solutions Collecting From Web of "是否有可能build立一个控制台应用程序,双击时不显示控制台窗口?"

请参阅Win32控制台应用程序是否可以检测是否已从资源管理器运行?

或者我觉得官方的方法是检查父进程是cmd.exe还是explorer.exe

所以,我已经写了一个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。 不过,创建一个控制台或者没有用户界面也是一样的容易。

编辑:这完全没有回答在编辑时,当我开始写,当然不在那里的问题。 除此之外,我们的黑客只是检查是否用命令行参数调用它。

只需将其构建为Windows窗体应用程序,但不要给它一个GUI。 不幸的是,当它从命令行运行时,你将不会得到任何控制台输出…是一个问题吗?

我没有读过所有的东西,但是做了这个(不久前,需要更多的测试):

 DWORD proc[2],procsfound=GetConsoleProcessList(proc,ELEMS(proc)); if (procsfound>1) // I'm started as a command in cmd.exe else // started from explorer or other non-console parent 

IFF有一个以上的proc,我需要恢复我操作的控制台,否则不需要。 可能是有用的,至少它本身就是简单的。 从VS启动代码会产生一个附加的过程,从命令提示符运行它确实激活分支来清理我的烂摊子。 顺便说一句,从资源管理器或其他非控制台应用程序启动的控制台将有一个零长度的标题?

这会更像一个服务呢?

要么

关于没有可见表单的Windows窗体应用程序? 它仍然会显示在“任务管理器进程”列表中。