Вывод в командную строку, если запущен из командной строки - PullRequest
6 голосов
/ 04 декабря 2008

Я пишу приложение, которое может быть запущено как стандартное приложение WinForms или в автоматическом режиме из командной строки. Приложение было построено с использованием стандартного шаблона WinForms VS 2k5.

Когда приложение выполняется из командной строки, я хочу, чтобы оно выводило информацию, которая может быть захвачена скриптом, выполняющим приложение. Когда я делаю это непосредственно из Console.WriteLine (), вывод не появляется, хотя его можно перехватить, отправив по трубопроводу в файл.

С другой стороны, я могу заставить приложение открыть вторую консоль, выполнив P / Invoke для AllocConsole () из kernel32. Это не то, что я хочу, хотя. Я хочу, чтобы вывод отображался в том же окне, из которого было вызвано приложение.

Это существенный код, который позволяет мне вызывать консоль из командной строки:

<STAThread()> Public Shared Sub Main()

    If My.Application.CommandLineArgs.Count = 0 Then
        Dim frm As New ISECMMParamUtilForm()
        frm.ShowDialog()
    Else
        Try
            ConsoleControl.AllocConsole()
            Dim exMan As New UnattendedExecutionManager(ConvertArgs())
            IsInConsoleMode = True
            OutputMessage("Application started.")
            If Not exMan.SetSettings() Then
                OutputMessage("Execution failed.")
            End If
        Catch ex As Exception
            Console.WriteLine(ex.ToString())
        Finally
            ConsoleControl.FreeConsole()
        End Try

    End If

End Sub

Public Shared Sub OutputMessage(ByVal msg As String, Optional ByVal isError As Boolean = False)
    Trace.WriteLine(msg)
    If IsInConsoleMode Then
        Console.WriteLine(msg)
    End If

    If isError Then
        EventLog.WriteEntry("ISE CMM Param Util", msg, EventLogEntryType.Error)
    Else
        EventLog.WriteEntry("ISE CMM Param Util", msg, EventLogEntryType.Information)
    End If

End Sub

Ответы [ 2 ]

9 голосов
/ 06 января 2009

Раймонд Чен недавно опубликовал (через месяц после того, как вопрос был размещен здесь на SO) короткую статью об этом:

Как написать программу, которая может быть запущена как консоль или приложение с графическим интерфейсом?

Вы не можете, но вы можете попытаться подделать это.

Каждое приложение PE содержит поле в своем заголовке, который указывает, какой подсистема, она была разработана для запуска под. Ты можешь сказать IMAGE_SUBSYSTEM_WINDOWS_GUI отметить себя как приложение Windows GUI, или вы можете сказать IMAGE_SUBSYSTEM_WINDOWS_CUI сказать что вы консольное приложение. Если вы приложение GUI, то Программа будет работать без консоли.

Подсистема определяет, как ядро готовит исполнение среда для программы. Если Программа помечена как запущенная в консольная подсистема, потом ядро подключит консоль программы к консоль своего родителя, создавая новая консоль, если у родителя нет консоль. (Это неполное описание, но детали не отношение к обсуждению.) На С другой стороны, если программа помечена работает как приложение с графическим интерфейсом, то ядро запустит программу без какой-либо консоли вообще.

В этой статье он указывает на другую статью Junfeng Zhang, в которой обсуждается, как несколько программ (Visual Studio и ildasm) реализуют это поведение:

Как сделать приложение как графическим, так и консольным приложением?

В случае VisualStudio существует два двоичных файла: devenv.com и devenv.exe. Devenv.com - это консольное приложение. Devenv.exe это приложение с графическим интерфейсом. При вводе devenv из-за правила проверки Win32 выполняется devenv.com. Если нет ввода, devenv.com запускает devenv.exe и завершает свою работу. Если есть входы, devenv.com обрабатывает их как обычное консольное приложение.

В случае ildasm есть только один двоичный файл: ildasm.exe. Сначала он компилируется как приложение с графическим интерфейсом. Позже editbin.exe используется, чтобы отметить его как консольную подсистему. В своем основном методе он определяет, должен ли он работать в режиме консоли или в режиме графического интерфейса. Если необходимо запустить режим графического интерфейса, он перезапускается как приложение с графическим интерфейсом.

В комментариях к статье Раймонда Чена, laonianren имеет это, чтобы добавить к краткому описанию Junfeng Zhang того, как работает Visual Studio:

devenv.com - это универсальное приложение-заглушка в консольном режиме. Когда он запускается, он создает три канала для перенаправления консоли stdin, stdout и stderr. Затем он находит свое собственное имя (обычно devenv.com), заменяет «.com» на «.exe» и запускает новое приложение (т.е. devenv.exe), используя конец чтения канала stdin и конец записи stdout. и трубы stderr как стандартные ручки. Затем он просто сидит и ждет выхода devenv.exe и копирует данные между консолью и каналами.

Таким образом, даже несмотря на то, что devenv.exe является приложением с графическим интерфейсом, он может читать и писать «родительскую» консоль, используя стандартные дескрипторы.

И вы можете использовать devenv.com для myapp.exe, переименовав его в myapp.com. Но вы не можете на практике, потому что это принадлежит MS.

2 голосов
/ 04 декабря 2008

Обновление 1:

Как сказано в ответе Майкла Берра, Раймонд Чен недавно опубликовал небольшую статью об этом . Я рад видеть, что мое предположение не было полностью неверным.

Обновление 0:

Отказ от ответственности: Этот «ответ» в основном спекуляция. Я публикую его только потому, что прошло достаточно времени, чтобы установить, что не многие люди имеют ответ на вопрос, который выглядит как фундаментальный вопрос.

Я думаю, что «решение», если приложение является графическим или консольным, принимается во время компиляции, а не во время выполнения. Поэтому, если вы компилируете свое приложение как приложение с графическим интерфейсом, даже если вы не отображаете графический интерфейс, оно по-прежнему является приложением с графическим интерфейсом и не имеет консоли. Если вы решите скомпилировать его как консольное приложение, то как минимум у вас будут мигать окна консоли, прежде чем переходить в графический режим. И я не знаю, возможно ли это в управляемом коде.

Думаю, проблема фундаментальная, потому что консольное приложение должно «контролировать» вызывающее консольное приложение. И это необходимо сделать до запуска кода дочернего приложения.

...