如何在窗体应用程序中显示控制台输出/窗口?
卡住了一个非常基本的例子:
using System; using System.Windows.Forms; class test { static void Main() { Console.WriteLine("test"); MessageBox.Show("test"); } }
如果我使用默认选项(在命令行使用csc)编译这个,如预期的那样,它将编译成一个控制台应用程序。 另外,因为我导入了System.Windows.Forms
,它也会显示一个消息框。
现在,如果使用选项/target:winexe
,我认为这与从项目选项中selectWindows Application
相同,如预期的那样,我将仅看到消息框并没有控制台输出。
(实际上,从命令行启动的那一刻,我可以在应用程序完成之前发出下一个命令)。
所以,我的问题是 – 我知道你可以有一个控制台应用程序的“窗口”/窗体输出,但无论如何,从Windows应用程序显示控制台?
这一个应该工作。
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();
也许这太简单了…
创build一个Windows窗体项目…
然后:项目属性 – >应用程序 – >输出types – >控制台应用程序
然后可以有Console和Forms一起运行,为我工作
如果您不担心按命令打开控制台,则可以进入项目的属性并将其更改为Console Application
。
这仍然会显示您的表单以及popup一个控制台窗口。 您不能closures控制台窗口,但它可以作为一个优秀的logging器进行debugging。
只要记住在部署该程序之前将其closures。
您可以使用pinvoke调用AttachConsole
来获取连接到WinForms项目的控制台窗口: http : //www.csharp411.com/console-output-from-winforms-application/
您也可以考虑使用Log4net( http://logging.apache.org/log4net/index.html )来configuration不同configuration的日志输出。
基本上有两件事情可以在这里发生。
控制台输出winforms程序有可能将自己附加到创build它的控制台窗口(或者,如果需要,也可以连接到另一个控制台窗口,或者实际上连接到新的控制台窗口)。 一旦连接到控制台窗口Console.WriteLine()等按预期工作。 这种方法的一个问题是,程序立即将控制权交还给控制台窗口,然后继续写入,这样用户也可以在控制台窗口中input。 你可以用/ wait参数来处理这个问题。
链接启动命令语法
redirect的控制台输出这是当别人从你的程序输出其他地方的输出,例如。
yourapp> file.txt
在这种情况下,连接到控制台窗口会有效地忽略pipe道。 为了使这个工作,你可以调用Console.OpenStandardOutput()来获得输出应该pipe道到的stream的句柄。 这只适用于输出pipe道,所以如果你想处理这两种情况,你需要打开标准输出并写入它并附加到控制台窗口。 这意味着输出被发送到控制台窗口和pipe道,但它是我能find的最佳解决scheme。 在我用来做这个的代码下面。
// 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); } }
这对我来说,pipe输出到一个文件。 调用控制台
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; } } }
我在这里find了这个代码: http : //www.csharp411.com/console-output-from-winforms-application/我认为是值得在这里发布。
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)); } }
我认为你正在寻找的是所谓的pipe道,其中IO是可用的任何其他应用程序的stream。 这让用户通过命令,并返回到一个文本框。这是一个写回年实现相同的东西:
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(); }
您可以随时在应用程序types,控制台或窗口之间切换。 所以,你不会写特殊的逻辑来查看标准输出。 另外,在debugging器中运行应用程序时,您将在输出窗口中看到所有的stdout。 你也许只需要添加一个断点,而在断点属性中改变“When Hit …”时,你可以输出任何消息和variables。 您也可以选中/取消选中“继续执行”,您的断点将变成方形。 所以,断点消息不会在debugging输出窗口中的应用程序中任何东西变长。
//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; } } }