Вывод Console.WriteLine из приложений Windows WPF в фактическую консоль

Предыстория: я изо всех сил пытаюсь добавить возможности командной строки и пакетной обработки к существующему приложению Windows WPF. Когда я обнаруживаю некоторые параметры при запуске, я подавляю появление окна, выполняю некоторую обработку и немедленно закрываю. Теперь, поскольку нет пользовательского интерфейса, я хотел бы вывести некоторые сообщения на stdout / stderr. Рассмотрим следующий код:

namespace WpfConsoleTest
{
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            Console.WriteLine("Start");
            System.Threading.Thread.Sleep(1000);
            Console.WriteLine("Stop");
            Shutdown(0);
        }
    }
}

Когда я запускаю из командной строки, я ожидаю следующего вывода:

Start
Stop

Но вместо:

C:\test>WpfConsoleTest.exe

C:\test>

Однако вы можете перенаправить вывод:

C:\test>WpfConsoleTest.exe > out.txt

C:\test>type out.txt
Start
Stop

К сожалению, перенаправление на CON не работает:

C:\test>WpfConsoleTest.exe > CON

C:\test>

Другая проблема заключается в том, что WpfConsoleTest.exe завершает работу немедленно после запуска. Так:

C:\test>WpfConsoleTest.exe > out.txt & type out.txt

C:\test>

Но:

C:\test>WpfConsoleTest.exe > out.txt & ping localhost > nul & type out.txt
Start
Stop

Лучшее решение, которое мне удалось найти до сих пор, — использовать start /B /wait:

C:\test>start /B /wait WpfConsoleTest.exe > out.txt & type out.txt
Start
Stop

Этот подход в основном подходит — если вы обернете его в летучую мышь, вы можете сохранить код ошибки и так далее. Единственный серьезный недостаток заключается в том, что вы получаете результат после завершения приложения, то есть вы не можете отслеживать прогресс, вам нужно дождаться завершения всего, что происходит.

Поэтому мой вопрос: Как выводить на родительскую консоль из WPF Windows Application? Кроме того, почему так сложно получить stdout / stderr из WPF?

Я знаю, что могу изменить тип приложения на Console Application в настройках проекта, но это имеет неприятный побочный эффект — окно консоли отображается все время, даже если вы просто дважды щелкните exe. Это решение также не годится, поскольку оно создает новую консоль, даже если приложение было запустить из cmd.

См. также:  Как использовать указатель функции для возврата указателя функции?

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

Аналогичный вопрос: stackoverflow .com / questions / 160587 /.   —  person gwiazdorrr    schedule 02.05.2012

Ссылка на этот вопрос была уже в последнем абзаце моего вопроса.   —  person gwiazdorrr    schedule 02.05.2012

Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 4
  1. gwiazdorrr

    В прошлом я сделал его консольным приложением и вызвал P / Invoke, чтобы скрыть окно консоли, связанное с приложением, после того, как я показал свое окно WPF:

    //added using statements per comments...
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
        internal sealed class Win32
        {
            [DllImport("user32.dll")]
            static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    
            public static void HideConsoleWindow()
            {
                IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;
    
                if (hWnd != IntPtr.Zero)
                {
                    ShowWindow(hWnd, 0); // 0 = SW_HIDE
                }
            }
        }
    

    На данный момент это лучшее решение. Мне просто не нравится, что окно консоли появляется до того, как оно отображается, я думаю, что это может беспокоить и сбивать с толку обычного пользователя. person gwiazdorrr; 02.05.2012

    Классное решение, хотя я думаю, что согласен с @gwiazdorrr, но для служебных проектов я считаю приемлемым … просто не уверен в чистых производственных проектах. person gwiazdorrr; 21.03.2013

    Добавьте using System.Diagnostics; и using System.Runtime.InteropServices; для тех, кто хочет его скомпилировать и задается вопросом, в каких пространствах имен находятся команды. person gwiazdorrr; 13.02.2015

    Решение, приведенное ниже, намного лучше. Сохраните это приложение Windows и AttachConsole при запуске. Таким образом, окно консоли не появится на короткое время перед пользовательским интерфейсом (не выглядит профессиональным). person gwiazdorrr; 20.09.2015

  2. gwiazdorrr

    Приложение WPF не будет иметь консоли по умолчанию, но вы можете легко создать ее, а затем писать в нее, как в консольном приложении. Раньше я использовал этот вспомогательный класс:

    public class ConsoleHelper
    {
        /// <summary>
        /// Allocates a new console for current process.
        /// </summary>
        [DllImport("kernel32.dll")]
        public static extern Boolean AllocConsole();
    
        /// <summary>
        /// Frees the console.
        /// </summary>
        [DllImport("kernel32.dll")]
        public static extern Boolean FreeConsole();
    }
    

    Чтобы использовать это в своем примере, вы должны уметь это сделать:

    namespace WpfConsoleTest
    {
        public partial class App : Application
        {
            protected override void OnStartup(StartupEventArgs e)
            {
                ConsoleHelper.AllocConsole(); 
                Console.WriteLine("Start");
                System.Threading.Thread.Sleep(1000);
                Console.WriteLine("Stop");
                ConsoleHelper.FreeConsole();
                Shutdown(0);
            }
        }
    }
    

    И теперь, если вы запустите его из командной строки, вы должны увидеть «Пуск» и «Стоп», написанные на консоли.

    Да, но я увижу новое окно консоли, даже если я запущу его из командной строки. Я хочу видеть результат в существующей консоли. person gwiazdorrr; 02.05.2012

    Хммм … У меня это сработало в WinForms, но похоже, что WPF делает что-то другое. Вы можете попробовать AttachConsole (msdn .microsoft.com / en-us / library / windows / desktop /), но вам нужно будет получить дескриптор процесса, который запустил ваше приложение (предположительно cmd.exe). person gwiazdorrr; 02.05.2012

    Чтобы получить родительский процесс, это может помочь: rhyous.com/2010/04/30/ person gwiazdorrr; 02.05.2012

    Работает просто отлично. Только для новичков … Это необходимый код … protected override void OnStartup (StartupEventArgs e) {base.OnStartup (e); ConsoleHelper.AllocConsole (); } защищенное переопределение void OnExit (ExitEventArgs e) {ConsoleHelper.FreeConsole (); base.OnExit (e); } person gwiazdorrr; 16.02.2016

    Это предложение не для всех. Здесь мы всегда создаем новую консоль с помощью AllocConsole, независимо от того, открыта ли она у нас. Это означает, что вы по-прежнему не можете console.writeline в командной строке, когда вы запускаете приложение WPF из командной строки, а в конце программы все сообщения исчезают (поскольку дополнительная консоль была закрыта). person gwiazdorrr; 24.11.2016

    Я сделал это, но я просто вижу окно консоли без слов. Я попробовал также покрасить консоль — но она осталась черной. person gwiazdorrr; 25.07.2017

    Это работает только один раз. Если я снова запущу его, у меня вылетит. Как это исправить? person gwiazdorrr; 07.12.2020

  3. gwiazdorrr

    В свойствах проекта вы можете изменить тип проекта с приложения Windows на консольное приложение, и, как ни странно, единственное отличие состоит в том, что вы получаете консоль для использования на протяжении всего жизненного цикла приложения. Однако я не пробовал это с WPF.

    Если вы хотите открывать и закрывать консоль, вам следует использовать Alloc/FreeConsole, но обычно проще изменить тип проекта.

    Как я уже писал, переход на консольное приложение создаст окно консоли, если вы дважды щелкните exe. Я хочу, чтобы вывод выводился на существующую консоль, если ее нет, не создавайте новую. person gwiazdorrr; 02.05.2012

  4. gwiazdorrr

    Немного покопавшись, я нашел этот ответ. Код сейчас:

    namespace WpfConsoleTest
    {
        public partial class App : Application
        {
            [DllImport("Kernel32.dll")]
            public static extern bool AttachConsole(int processId);
    
            protected override void OnStartup(StartupEventArgs e)
            {
                AttachConsole(-1);
                Console.WriteLine("Start");
                System.Threading.Thread.Sleep(1000);
                Console.WriteLine("Stop");
                Shutdown(0);
            }
        }
    }
    

    Непосредственный вызов exe по-прежнему имеет неприятный побочный эффект, связанный с немедленным возвратом вызова:

    C:\test>WpfConsoleTest.exe
    
    C:\test>Start
    Stop
    
    ^^^^
    The cursor will stay here waiting for the user to press enter!
    

    Решением снова является использование start:

    C:\test>start /wait WpfConsoleTest.exe
    Start
    Stop
    

    Спасибо за вклад!

    Спасибо, gwiazdorrr. Это, наверное, лучшее решение. Но я все еще недоволен тем неприятным эффектом, который это вызывает. Может быть, вы нашли лучшее решение? person gwiazdorrr; 13.10.2013

    @BorisModylevsky: Боюсь, что нет, я остановился на версии start, вызываемой пакетным скриптом. person gwiazdorrr; 14.10.2013

    Отлично, намного лучше, чем изменить приложение на консоль и скрыть окно консоли при запуске (ужасный опыт, поскольку окно консоли появится на короткое время до открытия пользовательского интерфейса) person gwiazdorrr; 20.09.2015

    Проблема с AttachConsole заключается в том, что после завершения работы приложения пользователь должен нажать «Enter», чтобы продолжить работу с консолью (кажется, что она зависла). Вы можете вызвать SendKeys.SendWait ({ENTER}); в конце, чтобы освободить консоль. person gwiazdorrr; 20.09.2015

    Я сделал это, но не вижу окно консоли person gwiazdorrr; 25.07.2017

    Я так рад, что нашел это, наткнулся на некоторые ужасно сложные обходные пути. У меня отлично получилось получить стандартный вывод из приложения C # WPF для Windows. Консольное ожидание ввода в конце не повлияло на мой вариант использования, поскольку я запускаю приложение WPF из другого приложения WPF и перенаправляю стандартный вывод из одного приложения WPF в другое. person gwiazdorrr; 20.03.2020

    Перед выходом я печатал текст «Приостановлено». Нажмите Enter, чтобы продолжить. или что-то в этом роде, чтобы пользователю было понятно, что нужно нажать Enter. person gwiazdorrr; 25.09.2020

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: