Подтвердить что ты не робот

Возможно ли создать консольное приложение, которое не отображает консольное окно при двойном щелчке?

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

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

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

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

alt text

Является ли это возможным?

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

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

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

В 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, вы сразу получите ответ cmd. Если есть stdin/stdout и запускается из cmd.exe, то родительский cmd.exe ожидает завершения процесса.

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


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

Я до сих пор не понял, как узнать, запущен ли он из explorer или cmd.exe, но я все ближе...


ОТВЕТЫ

Невозможно создать консольное приложение, которое не отображает окно консоли.

Можно создать консольное приложение, которое очень быстро скрывает свое окно, но не так быстро, как если бы оно никогда не появлялось.

Теперь, чтобы определить, было ли запущено консольное приложение из проводника, некоторые предложили взглянуть на консоль, в которой оно запущено
(из ответа mgb и статьи базы знаний 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.

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

4b9b3361

Ответ 2

Итак, я написал инструменты как с графическим интерфейсом, так и с 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(), когда закончите!

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

EDIT: Это полностью не отвечало на вопрос в редактировании, которого не было, когда я начал писать это, конечно. Кроме того, наш хак просто проверял, вызывались ли они с параметрами командной строки или нет.

Ответ 3

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

Ответ 4

Будет ли это больше напоминать сервис?

ИЛИ

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

Ответ 5

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

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 даст единый подключенный процесс, запуск которого из commandprompt активировал ветвь, чтобы очистить мой беспорядок. Btw, консоль, запущенная из проводника или другого не консольного приложения, будет иметь нулевую длину?