首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当双击时,是否可以构建一个不显示控制台窗口的控制台应用程序?

当双击时,是否可以构建一个不显示控制台窗口的控制台应用程序?
EN

Stack Overflow用户
提问于 2009-10-06 21:18:46
回答 6查看 8.9K关注 0票数 23

相关信息: 我应该在我的应用程序中包括命令行模式吗? 如何获取父进程标准输出? 控制台应用程序是否已从资源管理器中运行?

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

但是,当在资源管理器中双击它(而不是从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条):

代码语言:javascript
复制
  int left = Console.CursorLeft;
  int top = Console.CursorTop;
  bool ProcessWasRunFromExplorer = (left==0 && top==0);

这将告诉您进程是否在其自己的控制台中启动,而不是它是否是资源管理器。在资源管理器中双击就可以做到这一点,但是应用程序内部的Start.Process()也会做同样的事情。

如果您想以不同的方式对待这些情况,请使用此方法了解父进程的名称:

代码语言:javascript
复制
  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

若要在进程启动后快速隐藏窗口,请使用以下命令:

代码语言:javascript
复制
  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应用程序有用。

这对我有用。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2009-10-06 21:45:34

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

或者我认为正式的方法是检查父进程是cmd.exe或explorer.exe。

票数 3
EN

Stack Overflow用户

发布于 2009-10-06 21:21:32

只需将其构建为Windows窗体应用程序,但不要为其提供GUI。不幸的是,当从命令行运行时,您将无法获得任何控制台输出.这有问题吗?

票数 6
EN

Stack Overflow用户

发布于 2009-10-06 21:48:06

因此,我已经用GUI和CLI编写了工具。最困难的部分是找出要打开哪一个--但是在我们的例子中,CLI版本需要参数,所以如果没有任何参数,我就打开GUI。然后,如果他们想要一个控制台,就调用一个类似于以下内容的函数:

代码语言:javascript
复制
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也同样容易。

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

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1528152

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档