简体   繁体   English

如何在 forms 应用程序中显示控制台输出/窗口?

[英]How do I show a console output/window in a forms application?

To get stuck in straight away, a very basic example:要立即陷入困境,一个非常基本的例子:

using System;
using System.Windows.Forms;

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

If I compile this with default options (using csc at command line), as expected, it will compile to a console application.如果我使用默认选项(在命令行中使用 csc)编译它,正如预期的那样,它将编译为控制台应用程序。 Also, because I imported System.Windows.Forms , it will also show a message box.另外,因为我导入System.Windows.Forms ,它也会显示一个消息框。

Now, if I use the option /target:winexe , which I think is the same as choosing Windows Application from within project options, as expected I will only see the Message Box and no console output.现在,如果我使用选项/target:winexe ,我认为这与从项目选项中选择Windows Application相同,正如预期的那样,我将只看到消息框而看不到控制台 output。

(In fact, the moment it is launched from command line, I can issue the next command before the application has even completed). (事实上 ,从命令行启动它的那一刻,我可以在应用程序完成之前发出下一个命令)。

So, my question is - I know that you can have "windows"/forms output from a console application, but is there anyway to show the console from a Windows application?所以,我的问题是 - 我知道您可以从控制台应用程序中获得“windows”/forms output,但是无论如何可以从 Windows 应用程序中显示控制台吗?

this one should work.这个应该有效。

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

Perhaps this is over-simplistic...也许这过于简单化了......

Create a Windows Form project...创建 Windows 窗体项目...

Then: Project Properties -> Application -> Output Type -> Console Application然后:项目属性 -> 应用程序 -> 输出类型 -> 控制台应用程序

Then can have Console and Forms running together, works for me然后可以让控制台和表单一起运行,对我有用

If you are not worrying about opening a console on-command, you can go into the properties for your project and change it to Console Application如果您不担心按命令打开控制台,您可以进入项目的属性并将其更改为控制台应用程序

更改项目类型的屏幕截图 . .

This will still show your form as well as popping up a console window.这仍然会显示您的表单以及弹出一个控制台窗口。 You can't close the console window, but it works as an excellent temporary logger for debugging.您无法关闭控制台窗口,但它可以用作调试的出色临时记录器。

Just remember to turn it back off before you deploy the program.请记住在部署程序之前将其关闭。

You can call AttachConsole using pinvoke to get a console window attached to a WinForms project: http://www.csharp411.com/console-output-from-winforms-application/您可以使用 pinvoke 调用AttachConsole来获取附加到 WinForms 项目的控制台窗口: http : //www.csharp411.com/console-output-from-winforms-application/

You may also want to consider Log4net ( http://logging.apache.org/log4net/index.html ) for configuring log output in different configurations.您可能还需要考虑使用 Log4net ( http://logging.apache.org/log4net/index.html ) 在不同的配置中配置日志输出。

This worked for me, to pipe the output to a file.这对我有用,将输出通过管道传输到文件。 Call the console with调用控制台

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

Add this code to your application.将此代码添加到您的应用程序中。

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

I found this code here: http://www.csharp411.com/console-output-from-winforms-application/ I thought is was worthy to post it here as well.我在这里找到了这个代码: http : //www.csharp411.com/console-output-from-winforms-application/我认为也值得在这里发布它。

Create a Windows Forms Application, and change the output type to Console.创建一个 Windows 窗体应用程序,并将输出类型更改为控制台。

It will result in both a console and the form to open.这将导致控制台和窗体都打开。

在此处输入图片说明

There are basically two things that can happen here.基本上有两件事会在这里发生。

Console output It is possible for a winforms program to attach itself to the console window that created it (or to a different console window, or indeed to a new console window if desired).控制台输出 winforms 程序可以将自身附加到创建它的控制台窗口(或附加到不同的控制台窗口,或者如果需要,甚至附加到新的控制台窗口)。 Once attached to the console window Console.WriteLine() etc works as expected.一旦附加到控制台窗口 Console.WriteLine() 等按预期工作。 One gotcha to this approach is that the program returns control to the console window immediately, and then carries on writing to it, so the user can also type away in the console window.这种方法的一个问题是程序立即将控制权返回到控制台窗口,然后继续写入,因此用户也可以在控制台窗口中输入。 You can use start with the /wait parameter to handle this I think.我认为您可以使用带有 /wait 参数的 start 来处理此问题。

Link to start Command syntax 链接以启动命令语法

Redirected console output This is when someone pipes the output from your program somewhere else, eg.重定向控制台输出这是当有人将您的程序的输出通过管道传输到其他地方时,例如。

yourapp > file.txt你的应用程序> file.txt

Attaching to a console window in this case effectively ignores the piping.在这种情况下,附加到控制台窗口有效地忽略了管道。 To make this work you can call Console.OpenStandardOutput() to get a handle to the stream that the output should be piped to.为了完成这项工作,您可以调用 Console.OpenStandardOutput() 来获取输出应通过管道传输到的流的句柄。 This only works if the output is piped, so if you want to handle both of the scenarios you need to open the standard output and write to it and attach to the console window.这仅在输出通过管道传输时才有效,因此如果您想处理这两种情况,您需要打开标准输出并写入它并附加到控制台窗口。 This does mean that the output is sent to the console window and to the pipe but its the best solution I could find.这确实意味着输出被发送到控制台窗口和管道,但它是我能找到的最佳解决方案。 Below the code I use to do this.在我用来执行此操作的代码下方。

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

Building on Chaz's answer, in .NET 5 there is a breaking change , so two modifications are required in the project file, ie changing OutputType and adding DisableWinExeOutputInference .基于 Chaz 的回答,在 .NET 5 中有一个重大更改,因此项目文件中需要进行两次修改,即更改OutputType和添加DisableWinExeOutputInference Example:例子:

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

if what you want is simple debug output the following works for me.如果你想要的是简单的调试 output 以下对我有用。 I am using VS 2022 programming in C#我在C#使用VS 2022编程

add "using System.Diagnostics"添加“使用 System.Diagnostics”

then然后

  Debug.WriteLine("*****");
  Debug.WriteLine(...);
  Debug.WriteLine("");

THe output appears in the debug console of VS2022. output 出现在 VS2022 的调试控制台中。 There is a lot of stuff there so I use the Debug.WriteLine("*****") and Debug.WriteLine("") to help me find my output. You can also clear the debug output after start up.那里有很多东西,所以我使用 Debug.WriteLine("*****") 和 Debug.WriteLine("") 来帮助我找到我的 output。你也可以在启动后清除调试 output。

I am still working but running under VS there is no output when running wo debugging我还在工作但是在 VS 下运行没有 output 运行 wo 调试时

Why not just leave it as a Window Forms app, and create a simple form to mimic the Console.为什么不把它作为一个 Window Forms 应用程序,并创建一个简单的表单来模仿控制台。 The form can be made to look just like the black-screened Console, and have it respond directly to key press.可以使表单看起来像黑屏控制台,并直接响应按键。 Then, in the program.cs file, you decide whether you need to Run the main form or the ConsoleForm.然后,在 program.cs 文件中,您决定是否需要运行主窗体或 ConsoleForm。 For example, I use this approach to capture the command line arguments in the program.cs file.例如,我使用这种方法来捕获 program.cs 文件中的命令行参数。 I create the ConsoleForm, initially hide it, then pass the command line strings to an AddCommand function in it, which displays the allowed commands.我创建了 ConsoleForm,最初隐藏它,然后将命令行字符串传递给其中的 AddCommand 函数,该函数显示允许的命令。 Finally, if the user gave the -h or -?最后,如果用户给了 -h 或 -? command, I call the .Show on the ConsoleForm and when the user hits any key on it, I shut down the program.命令,我调用 ConsoleForm 上的 .Show ,当用户点击它的任何键时,我关闭程序。 If the user doesn't give the -?如果用户不给 -? command, I close the hidden ConsoleForm and Run the main form.命令,我关闭隐藏的 ConsoleForm 并运行主窗体。

在项目属性中将输出类型设置为Console将为您提供一个 Console 应用程序以及您创建的表单。

You can any time switch between type of applications, to console or windows.您可以随时在应用程序类型、控制台或窗口之间切换。 So, you will not write special logic to see the stdout.因此,您不会编写特殊逻辑来查看标准输出。 Also, when running application in debugger, you will see all the stdout in output window.此外,在调试器中运行应用程序时,您将在输出窗口中看到所有标准输出。 You might also just add a breakpoint, and in breakpoint properties change "When Hit...", you can output any messages, and variables.您也可以只添加一个断点,并在断点属性中更改“When Hit...”,您可以输出任何消息和变量。 Also you can check/uncheck "Continue execution", and your breakpoint will become square shaped.您也可以选中/取消选中“继续执行”,您的断点将变成方形。 So, the breakpoint messages without changhing anything in the application in the debug output window.因此,断点消息不会在调试输出窗口中更改应用程序中的任何内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在控制台应用程序中隐藏输出(而不是窗口)? - How to hide output (not the window) in a console application? 如何在 C# 中获取控制台应用程序窗口? - How do I get console application window in C#? 如何获取控制台应用程序窗口的句柄 - How do I get the handle of a console application's window 如何更改控制台应用程序以将输出发送到Winforms列表框? - How do I change a console application to send the output to a winforms listbox? 控制台应用程序输出-如何发布为Web服务 - console application output - how do I publish as a webservice 如何运行控制台应用程序,捕获输出并将其以文字形式显示? - How do I run a Console Application, capture the output and display it in a Literal? 如何在Visual Studio输出窗口中运行控制台应用程序,而不是打开新的命令提示符? - How do you run a console application in the Visual Studio output window, instead of opening a new command prompt? 如何获得命令控制台在Windows Forms应用程序中写行? (Visual C#) - How Do I Get The Command Console To Write Lines In Windows Forms Application? (Visual c#) 当程序在非调试模式下运行时,如何显示控制台窗口? - How do I make the Console window show when a program is running in non-debug mode? C#:我想像文件路径一样将消息传递给我的表单应用程序,比如控制台应用程序,我该怎么做? - C#: I want to pass messages like a file path to my forms application like a console application, how would I do that?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM