Вопрос по c#, wpf – Вывести Console.WriteLine из приложений Windows WPF на реальную консоль

27

Справочная информация: я пытаюсь добавить возможности командной строки и пакетной обработки в существующий WPFWindows Application, При обнаружении некоторых опций при запуске я подавляю появление окна, выполняю некоторую обработку и сразу же завершаю работу. Теперь, поскольку пользовательский интерфейс отсутствует, я хотел бы выводить некоторые сообщения в 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>

Выcan перенаправить вывод, хотя:

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

C:\test>type out.txt
Start
Stop

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

C:\test>WpfConsoleTest.exe > CON

C:\test>

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

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

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

Поэтому мой вопрос:How to output to parent console from WPF Windows Application? Кроме того, почему так сложно получить stdout / stderr из WPF?

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

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

Ссылка на этот вопрос уже была в последнем абзаце моего вопроса. gwiazdorrr
Подобный вопрос:stackoverflow.com/questions/160587/… Lukasz Madon

Ваш Ответ

4   ответа
8

но вы можете легко создать для нее консоль и затем писать в нее, как в консольном приложении. Я использовал этот вспомогательный класс раньше:

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);
        }
    }
}

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

Это предложение не решение для всех. Здесь мы всегда создаем новую консоль с AllocConsole независимо от того, есть ли у нас уже открытая. Это означает, что вы все равно не можете сохранить console.writeline в командной строке при запуске приложения WPF из командной строки и в конце программы все сообщения исчезают (поскольку дополнительная консоль была закрыта).
Да, но я увижуnew окно консоли, даже если я запускаю его из командной строки. Я хочу увидеть результат вexisting приставка. gwiazdorrr
Хммм ... Это хорошо сработало для меня в WinForms, но кажется, что WPF делает что-то другое. Вы можете попробовать AttachConsole (msdn.microsoft.com/en-us/library/windows/desktop/…), но вам нужно получить дескриптор процесса, который запустил ваше приложение (предположительно, cmd.exe)
Чтобы получить родительский процесс, это может помочь:rhyous.com/2010/04/30/…
Работает просто отлично. Просто для некоторых новичков ... Это необходимый код ... защищенное переопределение void OnStartup (StartupEventArgs e) {base.OnStartup (e); ConsoleHelper.AllocConsole (); } защищенное переопределение void OnExit (ExitEventArgs e) {ConsoleHelper.FreeConsole (); base.OnExit (е); }
16

чтобы скрыть окно консоли, связанное с приложением, после того как я показал свое окно 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
            }
        }
    }
добавлятьusing System.Diagnostics; а такжеusing System.Runtime.InteropServices; для тех, кто хочет его скомпилировать и интересуется, в каких пространствах имен находятся команды.
Это лучшее решение на сегодняшний день. Мне просто не нравится, когда окно консоли появляется перед отображаемым окном, я думаю, что оно может беспокоить и сбивать с толку обычного пользователя. gwiazdorrr
Решение ниже гораздо лучше. Держите это приложение Windows и AttachConsole при запуске. Таким образом, окно консоли не будет отображаться на короткое время перед пользовательским интерфейсом (не выглядит профессионально)
Отличное решение, хотя я думаю, что согласен с @gwiazdorrr, но для коммунальных проектов я думаю, что это приемлемо ... просто не уверен насчет чистого "производства" проекты.
24

этот ответ, Код сейчас:

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!
Проблема с AttachConsole заключается в том, что после завершения приложения пользователь должен нажать «ввести». продолжить работу с консолью (кажется, зависает). Вы можете вызвать SendKeys.SendWait (& quot; {ENTER} & quot;); в конце освободить консоль.
Спасибо, gwiazdorrr. Это, вероятно, лучшее решение. Но я все еще не доволен тем неприятным эффектом, который он вызывает. Возможно, вы нашли лучшее решение?
@BorisModylevsky: боюсь, нет, я согласился сstart версия вызывается пакетным скриптом. gwiazdorrr
-1

s на консольное приложение, и AFAIK, единственное отличие состоит в том, что вы получаете консоль для использования в течение всего срока службы приложения. Я не пробовал это с WPF, хотя.

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

Как я уже писал, переход на консольное приложение создаст окно консоли, если дважды щелкнуть исполняемый файл. То, что я хочу, - это вывод на печатьexisting консоль, если ее нет, не создавайте новую. gwiazdorrr

Похожие вопросы