Можно ли создать консольное приложение, которое не отображает окно консоли при двойном щелчке? - PullRequest
19 голосов
/ 07 октября 2009

Связанный:
Должен ли я включить режим командной строки в моих приложениях?
Как получить стандартный вывод родительского процесса?
Может ли консольное приложение определить, запущено ли оно из Проводника?

Я хочу создать консольное приложение, которое обычно запускается из командной строки.

Но, если дважды щелкнуть его из Проводника (в отличие от запуска из командной строки cmd.exe), я бы хотел, чтобы программа НЕ отображала окно консоли.

Я хочу избежать этого:

alt text

Возможно ли это?

РЕДАКТИРОВАТЬ Я полагаю, еще один способ задать вопрос: Возможно ли, чтобы программа знала, как она была вызвана - двойным щелчком или командной строкой ?

Я работаю в .NET, в Windows.

РЕДАКТИРОВАТЬ 2: С это Старое новое сообщение в блоге Я узнал кое-что хорошее. Вот что я знаю сейчас ...

В Windows EXE-файлы помечаются как GUI или не-GUI. Для csc.exe это выбирается с помощью /target:winexe или /target:exe. Перед выполнением первой инструкции в процессе ядро ​​Windows устанавливает среду выполнения. В этот момент, если EXE помечен как GUI, ядро ​​устанавливает для stdin / stdout для процесса значение NULL, а если не для GUI (командной строки), ядро ​​создает консоль и устанавливает для этого stdin / stdout для этого процесса. приставка.

При запуске процесса, если нет стандартного ввода / вывода (== /target:winexe), вызов немедленно возвращается. Итак, запустив приложение с графическим интерфейсом из cmd.exe, вы сразу получите ответ cmd. Если есть stdin / stdout и запускается из cmd.exe, то родительский cmd.exe ожидает завершения процесса.

«Немедленный возврат» важен, потому что если вы закодируете приложение с графическим интерфейсом для присоединения к консоли его родителя, вы сможете выполнить console.writeline и т. Д. Но приглашение cmd.exe активно. Пользователь может вводить новые команды, запускать новый процесс и так далее. Другими словами, от winexe простое подключение к родительской консоли с помощью AttachConsole(-1) не превратит его в консольное приложение.


На данный момент я думаю, что единственный способ разрешить приложению использовать консоль, если она вызывается из cmd.exe, и НЕ использовать ее при двойном щелчке, это определить exe как обычный exe консоли ( /target:exe) и скрыть окно при запуске, если это необходимо. Вы все еще получаете окно консоли, появляющееся кратко.

Я до сих пор не понял, как узнать, запущен ли он из explorer или 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) вернется в командную строку сразу после запуска приложения с графическим интерфейсом. Другими словами, командная строка активна и готова к вводу, в то время как только что запущенный процесс может выдавать вывод. Это сбивает с толку и, вероятно, полезно только для отладки приложений winforms.

Это сработало для меня.

Ответы [ 5 ]

5 голосов
/ 07 октября 2009

Итак, я написал инструменты как с GUI, так и с CLI. Сложнее всего было выяснить, какой из них открыть - в нашем случае, однако, версия CLI имела требуемые параметры, поэтому я просто открыл графический интерфейс, если не было никаких параметров. Затем, если им нужна консоль, вызовите функцию, которая выглядит примерно так:

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 (), когда вы закончите!

В нашем случае, конечно, если мы не создаем консоль, мы создаем графический интерфейс. Впрочем, было бы так же легко создать консоль или без пользовательского интерфейса.

РЕДАКТИРОВАТЬ: Это полностью не отвечало на вопрос в редактировании, которого не было, когда я начал писать это, конечно. Кроме этого наш хак просто проверял, вызывается ли он с параметрами командной строки или нет.

4 голосов
/ 07 октября 2009

Просто создайте его как приложение Windows Forms, но не предоставляйте ему графический интерфейс. К сожалению, вы не получите консольного вывода при запуске из командной строки ... это проблема?

3 голосов
/ 07 октября 2009

См. Может ли консольное приложение Win32 определить, запущено ли оно из проводника или нет?

Или я думаю, что официальный способ проверить родительский процесс - cmd.exe или explorer.exe

0 голосов
/ 03 июня 2013

Я не прочитал все до конца, но сделал это (некоторое время назад, требуется дополнительное тестирование):

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

В случае, если подключено более одного процесса, мне нужно восстановить консоль, которой я манипулировал, иначе нет. Может быть полезно, по крайней мере, сама простота. Запуск кода из VS приведет к одному прикрепленному процессу, при запуске его из команды commandprompt была активирована ветка, чтобы очистить мой беспорядок. Кстати, консоль, запущенная из проводника или другого не консольного приложения, будет иметь заголовок нулевой длины?

0 голосов
/ 07 октября 2009

Тогда это будет больше похоже на Услугу?

OR

А как насчет приложения Windows Forms, которое не имеет видимой формы? Он все равно будет отображаться в списке процессов диспетчера задач.

...