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


131

すぐに行き詰まる、非常に基本的な例:

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


2
2つの違いは何だと思いますか?なぜコンソールとしてコンパイルしてフォームを表示しないのですか?
Doggett

7
@Doggett、シンプル-実際にアプリケーションで使用することにならない場合でも、なぜ/どうやってそれを行うのかを学びたいと思っています...現在、追加のコマンドを提供するオプションを考えています/ VLCなどの出力、ただしTBH、私はそれを必要としません-繰り返しますが、単に学習してそれを理解したいだけです!
Wil

:私はこのチュートリアルを使用して達成saezndaree.wordpress.com/2009/03/29/...
vivanov

回答:


153

これはうまくいくはずです。

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

8
すごい、この質問はたくさん尋ねられたようです。これは、私が見つけた質問に対する唯一の実際の答えです。+ 1
RobJohnson

5
主な問題:それを閉じると、すべてのアプリケーションが閉じます。
マーク

4
私はWindows 8とWindows 10でテストしました:-AttachConsoleはコマンドボックスから動作します-AllocConsoleはVisual Studioから動作します。allocが必要な場合、AttachConsoleはfalseを返します。また、コンソールモードでアプリケーションを終了する前に、FreeConsole()を呼び出す必要があります。私のプログラムでは、Matthew Strawbridgeのコード(以下を参照)を使用し、AttachConsole()行を次のように変更しました:if(!AttachConsole(-1))AllocConsole();
Berend Engelbrecht

これはユーザーコントロールで機能しますか?Granadosなどを使用して、SSHコントロールをwinformsコンポーネントとして作成する作業をしていますが、これはバックグラウンドコンポーネントのみです。コンポーネントのコンソールを表示して使用するための素敵なラッパーを追加したいと思います。
Kraang Prime

2
これはすばらしいことではありません。コマンドラインから実行すると、別のコンソールウィンドウがポップアップ表示され、コマンドラインから実行し>て出力をリダイレクトしようとすると、別のコンソールウィンドウが表示され、ファイルに出力がありません。
ウグリコヨーテ2018

139

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

Windowsフォームプロジェクトを作成...

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

次に、コンソールとフォームを一緒に実行できます


2
最も簡単なようですが、私の問題も修正しました。
dadude999 2015年

2
これは間違いなく最良の解決策です!その他は
賢いですが、非常に

3
シンプルでうまくいきました。これは受け入れられる答えになるはずです。
madu 2017

7
確かに、技術的にこれはポスターが求めるものを許可するために使用できます-それは素晴らしい解決策ではありません。これにより、WinformsアプリケーションをGUIで起動すると、コンソールウィンドウも開きます。この場合、Mike de Klerkの答えのようなものが必要になります。
Justin Greywolf 2017

2
これは、Winformsアプリがコマンドラインから実行したときにコンソールに出力を書き込んだり、コマンドラインでにリダイレクトされたときにファイルに書き込んだりできる唯一のソリューション>です。ただし、「コンソールアプリケーション」として実行する方法をときどき説明するだけのソリューション(つまり、この神秘的なVisual Studio設定を変更することでプログラム的に有効にする)を望んでいました。これが内部でどのように機能するか知っている人はいますか?
ウグリコヨーテ

63

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

プロジェクトタイプの変更のスクリーンショット

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

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


1
いいね。これにより、フォームアプリケーションの問題が解決されます。つまり、出力をファイルにリダイレクトすることをサポートしながら、コンソールウィンドウに出力できる必要があります。コンソールを手動で接続する必要はありません...
Kai Hartmann

2
@JasonHarrisonコンソールウィンドウを閉じると、プログラムが閉じます。また、プログラムの実行中、ウィンドウは常に開いています。
gunr2171 2016年

2
@ gun2171:ありがとう。このアプローチの欠点は、答えに記載されています。アプリケーションは、ダブルクリックして、[スタート]メニューなどで起動された場合は、コンソールウィンドウが表示されます
ジェイソン・ハリソンを

17

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

さまざまな構成でログ出力を構成するために、Log4net(http://logging.apache.org/log4net/index.html)を検討することもできます。


+1-うわー、私はconsole.showまたは同様のものを望んでいました!思ったよりずっと複雑!より良い/より簡単な答えがある場合に備えて、私は今のところは空けておきます。
Wil

これは私にとってはうまくいきましたが、AllocConsole()は新しいコンソールウィンドウを生成したため、うまくいきませんでした(AllocConsoleについてこれ以上掘り下げなかったので、そこに何か見落としているかもしれません)。
derFunk、2013

14

これは、出力をファイルにパイプするために機能しました。でコンソールを呼び出す

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"))
            {
#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;
            }
        }
    }

私はここにこのコードを見つけました:http : //www.csharp411.com/console-output-from-winforms-application/ 私もここに投稿する価値があると思いました。


5
これは、Windows 8とWindows 10で失敗することを除いて、うまく機能します。失敗すると、出力が表示されず、追加のプロンプトが表示されます(それが手がかりの場合)。誰かがAllocConsoleを提案しましたが、コマンドウィンドウをフラッシュしただけです。
Simon Heffer 2015年

上記のChazの回答も試してみましたが、Windows 7に新しいコンソールが表示されます(ただし、8または10ではできません)。コマンドラインでリダイレクトして実行するか、引数がない場合はguiとして実行するオプションが必要です。
Simon Heffer 2015年

私はこれを試しましたが、うまくいきませんでした。AttachConsole(ATTACH_PARENT_PROCESS)コンソール出力を取得しただけで、コマンドラインでリダイレクトすると>機能しません。この答えを試しても、コンソールでもファイルでも出力がまったく得られません。
ウグリコイト

12

ここでは基本的に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);
    }
}

コンソールに書き込むことができませんでした。親プロセスをアタッチすることが最初のトリックでした。ありがとうございました。
Pupper 2013年

この回答では、のすべての呼び出しを書き換えてConsole.WriteLine、代わりにWriteLine上記で定義した新しい呼び出しを呼び出す必要があるようです。コマンドラインでアプリケーションを実行し、ファイルにリダイレクトするときに、このコードでは何もファイルにリダイレクトできないようにしようとし>ましたが、
ウグリコイト

@uglycoyote、アプリケーションでGUIConsoleWriterをできるだけ早く構築していることを確認してください。そうしないと、不可解なウィンドウタイプの理由で機能しません。呼び出しをカプセル化Console.WriteLineすることは、テストして、ログに記録する場所を簡単に変更できるので、ちょうど良い習慣だと主張します(たとえば、PaperTrailなどのクラウドベースのログサービスへのログ記録を開始したい場合など) )
出典:2018

これはWin10で私にとっては問題なくうまくいきましたStreamWriter _stdOutWriter;
TS

答えはパイピングですが、ファイルではなく、MOREを使用するだけです。もっと ; stackoverflow.com/a/13010823/1845672
Roland

9

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

これは、になりますコンソールとフォームの両方オープンします。

ここに画像の説明を入力してください


これはまさに私が探しているものです。シンプルでWINAPIを使用していません。
Michael Coxon

私は多くの例を試しましたが、どれも私の期待に応える結果をもたらしませんでした。しかし、このソリューションはまさに私が欲しかったものであり、はるかに簡単なソリューションです。
inexcitus

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

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

1
コマンドプロンプトからは正常に機能しますが、[スタート]> [ファイル名を指定して実行]またはVisual Studioでは機能しません。すべてのケースで機能させるには、AttachConsoleの行を次のように置き換えます。if(!AttachConsole(-1))AllocConsole(); AllocConsole()が呼び出された場合、FreeConsole()も呼び出される必要があります。そうでない場合、コンソールホストはプログラムの終了後も実行を続けます。
Berend Engelbrecht 2015

2
initialiseOutおよびinitialiseErrorは、使用されていないため、どのように使用するのですか?
エドウィン

StandardHandle : uintここでは間違っています... x86とx64の両方で動作するにはIntPtrである必要があります
Dmitry Gusarov

1

アプリケーションのタイプをコンソールまたはウィンドウにいつでも切り替えることができます。したがって、stdoutを表示するための特別なロジックは記述しません。また、デバッガーでアプリケーションを実行すると、出力ウィンドウにすべてのstdoutが表示されます。また、ブレークポイントを追加するだけで、ブレークポイントのプロパティが「ヒットしたとき...」で変更され、メッセージや変数を出力できます。また、[実行を続行]をオン/オフにすると、ブレークポイントが四角形になります。したがって、デバッグ出力ウィンドウのアプリケーションで何も変更せずにブレークポイントメッセージが表示されます。


0

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


2
こんにちは、StackOverflowへようこそ。回答として質問を投稿することは避け、コメントセクションを使用してください。
ペドロロドリゲス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.