web-dev-qa-db-ja.com

フォームアプリケーションでコンソール出力/ウィンドウを表示するにはどうすればよいですか?

すぐに立ち往生するための非常に基本的な例:

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アプリケーションからコンソールを表示する方法はありますか?

108
Wil

これは動作するはずです。

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

おそらくこれは過度に単純すぎる...

Windows Formプロジェクトを作成...

次に、プロジェクトのプロパティ->アプリケーション->出力タイプ->コンソールアプリケーション

その後、コンソールとフォームを一緒に実行することができ、私のために働く

111
Chaz

コマンドを使用してコンソールを開くことを心配していない場合は、プロジェクトのプロパティに移動して、コンソールアプリケーションに変更できます。

screenshot of changing the project type

これにより、フォームが表示され、コンソールウィンドウがポップアップ表示されます。コンソールウィンドウを閉じることはできませんが、デバッグ用の優れた一時的なロガーとして機能します。

プログラムを展開する前に、忘れずにオフにしてください。

51
gunr2171

Pinvokeを使用してAttachConsoleを呼び出して、WinFormsプロジェクトに接続されたコンソールウィンドウを取得できます。 http://www.csharp411.com/console-output-from-winforms-application/

Log4net( http://logging.Apache.org/log4net/index.html )を考慮して、さまざまな構成でログ出力を構成することもできます。

15
Adam Vandenberg

これは、出力をファイルにパイプするのに役立ちました。コンソールを呼び出す

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/ ここにも投稿する価値があると思った.

11
Mike de Klerk

ここでは、基本的に2つのことが起こります。

コンソール出力winformsプログラムは、それを作成したコンソールウィンドウ(または別のコンソールウィンドウ、または必要に応じて実際に新しいコンソールウィンドウ)に自分自身をアタッチすることができます。コンソールウィンドウにアタッチすると、Console.WriteLine()などは正常に機能します。このアプローチの落とし穴の1つは、プログラムがすぐにコンソールウィンドウに制御を返し、書き込みを続行するため、ユーザーがコンソールウィンドウに入力することもできることです。これを処理するには、/ waitパラメーターを指定してstartを使用できます。

コマンド構文を開始するリンク

リダイレクトされたコンソール出力これは、誰かがあなたのプログラムからの出力をどこか他の場所にパイプするときです。

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);
    }
}
9
cedd
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));
    }
}
2
rag
//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;
        }
    }
}
2
Kamil Kh

アプリケーションの種類をコンソールまたはウィンドウにいつでも切り替えることができます。そのため、stdoutを表示するための特別なロジックは作成しません。また、デバッガーでアプリケーションを実行すると、出力ウィンドウにすべての標準出力が表示されます。また、単にブレークポイントを追加するだけで、ブレークポイントプロパティが「ヒット時...」に変更されると、メッセージと変数を出力できます。また、「Continue execution」をオン/オフにすると、ブレークポイントが正方形になります。したがって、デバッグ出力ウィンドウでは、アプリケーション内の何も変更せずにブレークポイントメッセージが表示されます。

1
armagedescu

Windowsフォームアプリケーションを作成し、出力タイプをコンソールに変更できます。

コンソールとフォームの両方が開きます。

enter image description here

0
Pedro Rodrigues

Window Formsアプリとしてそのままにして、コンソールを模倣するシンプルなフォームを作成してみませんか。フォームは、ブラックスクリーンのコンソールのように見えるようにし、キーを押したときに直接応答するようにできます。次に、program.csファイルで、メインフォームまたはConsoleFormを実行する必要があるかどうかを決定します。たとえば、このアプローチを使用して、program.csファイル内のコマンドライン引数をキャプチャします。 ConsoleFormを作成し、最初に非表示にしてから、コマンドライン文字列をその中のAddCommand関数に渡します。これにより、許可されたコマンドが表示されます。最後に、ユーザーが-hまたは-?を指定した場合コマンド、ConsoleFormで.Showを呼び出し、ユーザーがキーを押すと、プログラムをシャットダウンします。ユーザーが-を与えない場合コマンド、非表示のConsoleFormを閉じてメインフォームを実行します。

0
gverge