Как показать консольный вывод/окно в приложении форм?

Чтобы застрять сразу, очень простой пример:

using System;
using System.Windows.Forms;

class test
{ 
    static void Main()
    { 
        Console.WriteLine("test");
        MessageBox.Show("test");
    }
}

Если я скомпилирую это с настройками по умолчанию (используя csc в командной строке), как и ожидалось, он будет компилироваться в консольное приложение. Кроме того, поскольку я импортировал System.Windows.Forms, он также отобразит окно сообщения.

Теперь, если я использую опцию /target:winexe, которая, как я думаю, такая же, как выбор Windows Application из параметров проекта, как ожидается, я увижу только окно сообщения и никакой вывод консоли.

(Фактически, момент, когда он запускается из командной строки, я могу выполнить следующую команду до того, как приложение даже завершится).

Итак, мой вопрос: я знаю, что вы можете иметь "окна" /формы вывода из консольного приложения, но есть ли все-таки показать консоль из приложения Windows?

Ответ 1

это должно работать.

using System.Runtime.InteropServices;

private void Form1_Load(object sender, EventArgs e)
{
    AllocConsole();
}

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();

Ответ 2

Возможно, это слишком упрощенное...

Создайте проект Windows Form...

Затем: Свойства проекта → Приложение → Тип вывода → Консольное приложение

Затем может работать Консоль и Формы, работает для меня

Ответ 3

Если вы не беспокоитесь об открытии консоли по команде, вы можете перейти в свойства своего проекта и изменить его на Консольное приложение

screenshot of changing the project type.

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

Просто не забудьте отключить его перед развертыванием программы.

Ответ 5

Это сработало для меня, чтобы направить вывод в файл. Вызовите консоль с помощью

cmd/c "C:\path\to\your\application.exe" > myfile.txt

Добавьте этот код в свое приложение.

    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(UInt32 dwProcessId);
    [DllImport("kernel32.dll")]
    private static extern bool GetFileInformationByHandle(
        SafeFileHandle hFile,
        out BY_HANDLE_FILE_INFORMATION lpFileInformation
        );
    [DllImport("kernel32.dll")]
    private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
    [DllImport("kernel32.dll")]
    private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
    [DllImport("kernel32.dll")]
    private static extern bool DuplicateHandle(
        IntPtr hSourceProcessHandle,
        SafeFileHandle hSourceHandle,
        IntPtr hTargetProcessHandle,
        out SafeFileHandle lpTargetHandle,
        UInt32 dwDesiredAccess,
        Boolean bInheritHandle,
        UInt32 dwOptions
        );
    private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
    private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
    private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
    private const UInt32 DUPLICATE_SAME_ACCESS = 2;
    struct BY_HANDLE_FILE_INFORMATION
    {
        public UInt32 FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public UInt32 VolumeSerialNumber;
        public UInt32 FileSizeHigh;
        public UInt32 FileSizeLow;
        public UInt32 NumberOfLinks;
        public UInt32 FileIndexHigh;
        public UInt32 FileIndexLow;
    }
    static void InitConsoleHandles()
    {
        SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup;
        BY_HANDLE_FILE_INFORMATION bhfi;
        hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        hStdErr = GetStdHandle(STD_ERROR_HANDLE);
        // Get current process handle
        IntPtr hProcess = Process.GetCurrentProcess().Handle;
        // Duplicate Stdout handle to save initial value
        DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup,
        0, true, DUPLICATE_SAME_ACCESS);
        // Duplicate Stderr handle to save initial value
        DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup,
        0, true, DUPLICATE_SAME_ACCESS);
        // Attach to console window – this may modify the standard handles
        AttachConsole(ATTACH_PARENT_PROCESS);
        // Adjust the standard handles
        if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
        {
            SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
        }
        else
        {
            SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
        }
        if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
        {
            SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
        }
        else
        {
            SetStdHandle(STD_ERROR_HANDLE, hStdErr);
        }
    }

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        // initialize console handles
        InitConsoleHandles();

        if (args.Length != 0)
        {

            if (args[0].Equals("waitfordebugger"))
            {
                MessageBox.Show("Attach the debugger now");
            }
            if (args[0].Equals("version"))
            {
#if DEBUG
                String typeOfBuild = "d";
#else
                String typeOfBuild = "r";
#endif
                String output = typeOfBuild + Assembly.GetExecutingAssembly()
                    .GetName().Version.ToString();
                //Just for the fun of it
                Console.Write(output);
                Console.Beep(4000, 100);
                Console.Beep(2000, 100);
                Console.Beep(1000, 100);
                Console.Beep(8000, 100);
                return;
            }
        }
    }

Я нашел этот код здесь: http://www.csharp411.com/console-output-from-winforms-application/ Я думал, что было бы достойно опубликовать это здесь.

Ответ 6

В основном есть две вещи, которые могут произойти здесь.

Консольный выход Программа winforms может присоединяться к окну консоли, который ее создал (или к другому окну консоли или, если необходимо, к новому окну консоли). После подключения к консольному окну Console.WriteLine() и т.д. Работает так, как ожидалось. Одна из них заключается в том, что программа немедленно возвращает управление в консольное окно, а затем продолжает записывать на нее, поэтому пользователь может также ввести в консольное окно. Вы можете использовать start с параметром /wait для обработки этого, я думаю.

Ссылка на начало синтаксиса команд

Перенаправленный вывод консоли Это когда кто-то передает данные из вашей программы в другое место, например.

yourapp > file.txt

Прикрепление к консольному окну в этом случае эффективно игнорирует трубопровод. Чтобы выполнить эту работу, вы можете вызвать Console.OpenStandardOutput(), чтобы получить дескриптор потока, к которому должен быть подключен вывод. Это работает только в том случае, если вывод передан по каналам, поэтому, если вы хотите обрабатывать оба сценария, вам нужно открыть стандартный вывод и записать на него и прикрепить к консольному окну. Это означает, что вывод отправляется в окно консоли и в трубку, но это лучшее решение, которое я могу найти. Ниже кода, который я использую для этого.

// This always writes to the parent console window and also to a redirected stdout if there is one.
// It would be better to do the relevant thing (eg write to the redirected file if there is one, otherwise
// write to the console) but it doesn't seem possible.
public class GUIConsoleWriter : IConsoleWriter
{
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AttachConsole(int dwProcessId);

    private const int ATTACH_PARENT_PROCESS = -1;

    StreamWriter _stdOutWriter;

    // this must be called early in the program
    public GUIConsoleWriter()
    {
        // this needs to happen before attachconsole.
        // If the output is not redirected we still get a valid stream but it doesn't appear to write anywhere
        // I guess it probably does write somewhere, but nowhere I can find out about
        var stdout = Console.OpenStandardOutput();
        _stdOutWriter = new StreamWriter(stdout);
        _stdOutWriter.AutoFlush = true;

        AttachConsole(ATTACH_PARENT_PROCESS);
    }

    public void WriteLine(string line)
    {
        _stdOutWriter.WriteLine(line);
        Console.WriteLine(line);
    }
}

Ответ 7

Вы можете создать приложение Windows Forms и изменить тип вывода на Console.

В результате откроется как консоль, так и форма.

enter image description here

Ответ 8

using System;
using System.Runtime.InteropServices;

namespace SomeProject
{
    class GuiRedirect
    {
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool AttachConsole(int dwProcessId);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GetStdHandle(StandardHandle nStdHandle);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetStdHandle(StandardHandle nStdHandle, IntPtr handle);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern FileType GetFileType(IntPtr handle);

    private enum StandardHandle : uint
    {
        Input = unchecked((uint)-10),
        Output = unchecked((uint)-11),
        Error = unchecked((uint)-12)
    }

    private enum FileType : uint
    {
        Unknown = 0x0000,
        Disk = 0x0001,
        Char = 0x0002,
        Pipe = 0x0003
    }

    private static bool IsRedirected(IntPtr handle)
    {
        FileType fileType = GetFileType(handle);

        return (fileType == FileType.Disk) || (fileType == FileType.Pipe);
    }

    public static void Redirect()
    {
        if (IsRedirected(GetStdHandle(StandardHandle.Output)))
        {
            var initialiseOut = Console.Out;
        }

        bool errorRedirected = IsRedirected(GetStdHandle(StandardHandle.Error));
        if (errorRedirected)
        {
            var initialiseError = Console.Error;
        }

        AttachConsole(-1);

        if (!errorRedirected)
            SetStdHandle(StandardHandle.Error, GetStdHandle(StandardHandle.Output));
    }
}

Ответ 9

//From your application set the Console to write to your RichTextkBox 
//object:
Console.SetOut(new RichTextBoxWriter(yourRichTextBox));

//To ensure that your RichTextBox object is scrolled down when its text is 
//changed add this event:
private void yourRichTextBox_TextChanged(object sender, EventArgs e)
{
    yourRichTextBox.SelectionStart = yourRichTextBox.Text.Length;
    yourRichTextBox.ScrollToCaret();
}

public delegate void StringArgReturningVoidDelegate(string text);
public class RichTextBoxWriter : TextWriter
{
    private readonly RichTextBox _richTextBox;
    public RichTextBoxWriter(RichTextBox richTexttbox)
    {
        _richTextBox = richTexttbox;
    }

    public override void Write(char value)
    {
        SetText(value.ToString());
    }

    public override void Write(string value)
    {
        SetText(value);
    }

    public override void WriteLine(char value)
    {
        SetText(value + Environment.NewLine);
    }

    public override void WriteLine(string value)
    {
        SetText(value + Environment.NewLine);
    }

    public override Encoding Encoding => Encoding.ASCII;

    //Write to your UI object in thread safe way:
    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the  
        // calling thread to the thread ID of the creating thread.  
        // If these threads are different, it returns true.  
        if (_richTextBox.InvokeRequired)
        {
            var d = new StringArgReturningVoidDelegate(SetText);
            _richTextBox.Invoke(d, text);
        }
        else
        {
            _richTextBox.Text += text;
        }
    }
}

Ответ 10

Я думаю, что то, что вы ищете, называется piping, где IO доступно как поток для любого другого приложения. Это позволит пользователю передать команду и вернуть ее обратно в текстовое поле. Это то, что написал год назад для достижения того же:

public static void ExecPro(string ProcessName, string args, string WrkDir, string cmdtxt, out string coutext)
    {
        Process cmd = new Process();

        cmd.StartInfo.FileName = ProcessName;
        cmd.StartInfo.Arguments = args;
        cmd.StartInfo.UseShellExecute = false;
        cmd.StartInfo.WorkingDirectory = WrkDir;
        cmd.StartInfo.CreateNoWindow = true;
        cmd.StartInfo.ErrorDialog = true;
        cmd.StartInfo.RedirectStandardOutput = true;
        cmd.StartInfo.RedirectStandardInput = true;
        cmd.StartInfo.RedirectStandardError = true;

        cmd.Start();
        StreamWriter cin = cmd.StandardInput;
        StreamReader cout = cmd.StandardOutput;

        cin.WriteLine(cmdtxt);
        cin.Close();
        coutext = cout.ReadToEnd();
        cmd.WaitForExit();
        cmd.Close();
    }

Ответ 11

Вы можете в любое время переключаться между типами приложений, консолями или окнами. Таким образом, вы не будете писать специальную логику, чтобы увидеть stdout. Кроме того, при запуске приложения в отладчике вы увидите все stdout в окне вывода. Вы также можете просто добавить точку останова, а в свойствах точки останова "When Hit..." вы можете выводить любые сообщения и переменные. Также вы можете проверить/снять флажок "Продолжить выполнение", и ваша точка останова станет квадратной. Таким образом, сообщения точки останова без изменения чего-либо в приложении в окне вывода отладки.

Ответ 12

Почему бы просто не оставить его как приложение Window Forms и создать простую форму, имитирующую консоль. Форма может выглядеть так же, как консоль с черным экраном, и она может реагировать непосредственно на нажатие клавиши. Затем в файле program.cs вы решаете, нужно ли запускать основную форму или ConsoleForm. Например, я использую этот подход для захвата аргументов командной строки в файле program.cs. Я создаю ConsoleForm, сначала скрываю его, затем передаю строки командной строки в функцию AddCommand, которая отображает разрешенные команды. Наконец, если пользователь дал -h или -? Команда, я вызываю .Show на ConsoleForm, и когда пользователь нажимает любую клавишу на нем, я закрываю программу. Если пользователь не дает -? По команде закрываю скрытую ConsoleForm и запускаю основную форму.