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

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

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

Ответ 1

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

Как сказал Майкл Берр, Raymond Chen недавно отправлено короткая статья об этом. Я рад видеть, что моя догадка не была полностью неправильной.

Обновить 0:

Отказ от ответственности: этот "ответ" в основном является предположением. Я публикую его только потому, что прошло достаточно времени, чтобы установить, что не многие люди имеют ответ на то, что выглядит фундаментальным вопросом.

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

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

Ответ 2

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

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

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

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

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

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

Как сделать приложение как GUI и консольное приложение?

В случае с 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 является GUI-приложением, он может читать и писать "родительскую" консоль с помощью стандартных ручек.

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