c# - from - ¿Cómo se muestra una salida/ventana de la consola en una aplicación de formularios?
open console from windows forms application (10)
Para quedarse enganchado de inmediato, un ejemplo muy básico:
using System;
using System.Windows.Forms;
class test
{
static void Main()
{
Console.WriteLine("test");
MessageBox.Show("test");
}
}
Si compilo esto con las opciones predeterminadas (usando csc en la línea de comandos), como se espera, se compilará en una aplicación de consola. Además, como importé System.Windows.Forms
, también mostrará un cuadro de mensaje.
Ahora, si utilizo la opción /target:winexe
, que creo que es lo mismo que elegir la Windows Application
desde las opciones del proyecto, como esperaba, solo veré el cuadro de mensaje y no saldrá la consola.
(De hecho, en el momento en que se lanza desde la línea de comandos, puedo emitir el siguiente comando antes de que la aplicación se haya completado).
Entonces, mi pregunta es: sé que puede hacer que "windows" / forms salga de una aplicación de consola, pero ¿hay alguna forma de mostrar la consola desde una aplicación de Windows?
Básicamente, hay dos cosas que pueden suceder aquí.
Salida de la consola Es posible que un programa de winforms se adjunte a la ventana de la consola que lo creó (oa una ventana de consola diferente, o incluso a una nueva ventana de consola, si así lo desea). Una vez conectado a la ventana de la consola Console.WriteLine () etc. funciona como se esperaba. Uno de los motivos de este enfoque es que el programa devuelve el control a la ventana de la consola de inmediato y luego continúa escribiendo para que el usuario también pueda escribir en la ventana de la consola. Puede usar start con el parámetro / wait para manejar esto, creo.
Enlace para iniciar la sintaxis del comando
Salida de consola redirigida Esto ocurre cuando alguien canaliza la salida de su programa a otro lugar, por ej.
yourapp> archivo.txt
Si se conecta a una ventana de consola en este caso, se ignoran las tuberías. Para que esto funcione, puede llamar a Console.OpenStandardOutput () para obtener un control de la transmisión a la que debe enviarse la salida. Esto solo funciona si la salida está canalizada, por lo que si desea manejar ambos escenarios, debe abrir la salida estándar, escribir en ella y adjuntarla a la ventana de la consola. Esto significa que la salida se envía a la ventana de la consola y a la tubería, pero es la mejor solución que pude encontrar. Debajo del código que uso para hacer esto.
// 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);
}
}
Creo que lo que está buscando se llama tubería, donde el IO está disponible como una secuencia para cualquier otra aplicación. Esto permite al usuario pasar el comando y obtener el retorno en un cuadro de texto. Esto es lo que un año atrás escribió para lograr lo mismo:
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();
}
En cualquier momento puede alternar entre el tipo de aplicaciones, la consola o las ventanas. Por lo tanto, no escribirá una lógica especial para ver el stdout. Además, al ejecutar la aplicación en el depurador, verá toda la stdout en la ventana de resultados. También puede agregar un punto de interrupción y en las propiedades de punto de interrupción cambiar "Cuando se acierte ...", puede generar cualquier mensaje y variables. También puede marcar / desmarcar "Continuar ejecución", y su punto de corte se convertirá en forma cuadrada. Entonces, los mensajes de punto de interrupción sin cambiar nada en la aplicación en la ventana de salida de depuración.
Esto funcionó para mí, para canalizar la salida a un archivo. Llamar a la consola con
cmd / c "C: / path / to / your / application.exe"> myfile.txt
Agregue este código a su aplicación.
[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;
}
}
}
Encontré este código aquí: http://www.csharp411.com/console-output-from-winforms-application/ Pensé que era digno de publicarlo aquí también.
Puede llamar a AttachConsole
usando pinvoke para obtener una ventana de consola adjunta a un proyecto de WinForms: http://www.csharp411.com/console-output-from-winforms-application/
También puede considerar Log4net ( http://logging.apache.org/log4net/index.html ) para configurar el resultado del registro en diferentes configuraciones.
Quizás esto es demasiado simplista ...
Crear un proyecto de Windows Form ...
Luego: Propiedades del proyecto -> Aplicación -> Tipo de salida -> Aplicación de consola
Entonces puede tener Consola y Formularios funcionando juntos, funciona para mí
Si no está preocupado por abrir una consola al comando, puede acceder a las propiedades de su proyecto y cambiarla a la Console Application
.
Esto mostrará su formulario y aparecerá una ventana de la consola. No puede cerrar la ventana de la consola, pero funciona como un excelente registrador para la depuración.
Solo recuerde apagarlo antes de implementar el programa.
este debería funcionar
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();
//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;
}
}
}
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));
}
}