Как показать вывод консоли / окно в приложении форм?
Чтобы застрять сразу, очень простой пример:
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"/ формы из консольного приложения, но есть ли способ показать консоль из приложения Windows?
16 ответов
Этот должен работать.
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();
Возможно, это слишком упрощенно...
Создать проект Windows Form...
Затем: Свойства проекта -> Приложение -> Тип вывода -> Консольное приложение
Тогда может иметь консоль и формы, работающие вместе, у меня работает
Если вы не беспокоитесь об открытии консоли по команде, вы можете зайти в свойства своего проекта и изменить его на "Консольное приложение".
Это все еще покажет вашу форму, а также появится окно консоли. Вы не можете закрыть окно консоли, но оно отлично работает как временный регистратор для отладки.
Просто не забудьте отключить его перед развертыванием программы.
Ты можешь позвонить AttachConsole
используя pinvoke, чтобы подключить консольное окно к проекту WinForms: http://www.csharp411.com/console-output-from-winforms-application/
Вы также можете рассмотреть Log4net ( http://logging.apache.org/log4net/index.html) для настройки вывода журнала в различных конфигурациях.
Вы можете создать приложение Windows Forms и изменить тип вывода на Console.
Это приведет к открытию как консоли, так и формы.
Это сработало для меня, чтобы направить вывод в файл. Вызвать консоль с
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"))
{
String TypeOfBuild = "";
#if DEBUG
TypeOfBuild = "d";
#else
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/ Я подумал, что стоит также опубликовать его здесь.
Здесь в основном могут произойти две вещи.
Вывод на консоль Программа 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);
}
}
//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;
}
}
}
Основываясь на ответе Чаза, в .NET 5 есть критическое изменение , поэтому в файле проекта требуются две модификации, т. Е. Изменение
OutputType
и добавление
DisableWinExeOutputInference
. Пример:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0-windows10.0.17763.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
<Platforms>AnyCPU;x64;x86</Platforms>
</PropertyGroup>
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));
}
}
Установка типа вывода как Console в свойствах проекта даст вам консольное приложение вместе с созданной вами формой.
если вам нужен простой отладочный вывод, для меня работает следующее. Я использую программирование VS 2022 на С#.
добавить «используя System.Diagnostics»
затем
Debug.WriteLine("*****");
Debug.WriteLine(...);
Debug.WriteLine("");
Вывод появляется в консоли отладки VS2022. Там много всего, поэтому я использую Debug.WriteLine("*****") и Debug.WriteLine(""), чтобы помочь мне найти мой вывод. Вы также можете очистить вывод отладки после запуска.
Я все еще работаю, но работаю под VS, при запуске wo отладки нет вывода
У меня недостаточно представителей, чтобы прокомментировать [https://stackoverflow.com/a/55362222/7623332], поэтому я говорю это здесь. Если вы посмотрите на это спустя годы, пытаясь следовать упомянутому ответу, знайте, что вам нужно будет установить для свойства DisableWinExeOutputInference значение «true» в файле проекта, иначе консоль не появится.
Чтобы иметь как окно, так и консоль в приложении WinForm, рабочее решение (с .Net6.0 и Windows в качестве целевой ОС) выглядит следующим образом:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class MyMainForm : Form
{
[DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
private static extern bool FreeConsole();
private int interval = default;
public MyMainForm()
{
InitializeComponent(); // default winform designer initialize method
Invalidate();
AllocConsole();
// You can write text to the console within the constructor.
System.Console.WriteLine("*** Closing the console will close application as well ***");
this.FormClosing += (s, e) => FreeConsole();
this.KeyDown += (s, e) => System.Console.WriteLine(interval++);
}
}
Почему бы просто не оставить его как приложение Window Forms и создать простую форму, имитирующую консоль. Форма может выглядеть так же, как консоль с черным экраном, и она может реагировать непосредственно на нажатие клавиши. Затем в файле program.cs вы решаете, нужно ли запускать основную форму или ConsoleForm. Например, я использую этот подход для захвата аргументов командной строки в файле program.cs. Я создаю ConsoleForm, сначала скрываю его, затем передаю строки командной строки в функцию AddCommand, которая отображает разрешенные команды. Наконец, если пользователь дал -h или -? Команда, я вызываю.Show на ConsoleForm, и когда пользователь нажимает любую клавишу на нем, я закрываю программу. Если пользователь не дает -? По команде закрываю скрытую ConsoleForm и запускаю основную форму.
Вы можете в любое время переключаться между типами приложений, консолью или окнами. Таким образом, вы не будете писать специальную логику, чтобы увидеть стандартный вывод. Также при запуске приложения в отладчике вы увидите все stdout в окне вывода. Вы также можете просто добавить точку останова, а в свойствах точки останова изменить "При попадании...", вы можете выводить любые сообщения и переменные. Также вы можете установить / снять флажок "Продолжить выполнение", и ваша точка останова станет квадратной. Таким образом, сообщения о точках останова ничего не изменяются в приложении в окне вывода отладки.