none
Windowsアプリケーションとコンソールアプリケーションの両立のさせ方 RRS feed

  • 質問

    • 行いたいこと
      コマンド引数にてWindowsアプリケーションとコンソールアプリケーションの立ち上がりを切り替える。
    • 現状の問題
      デバックコンソールのほうに”Hello World.”が表示されてしまいます。
    • 開発環境
      VS2017 Community
      .NET4.6.1
    • 設定
      アプリケーション:出力の種類→Windowsアプリケーション

    • 書いたプログラム
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace ConsoleGUI
    {
        static class Program
        {
            [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
            static extern bool AttachConsole(int processId);
            const int ATTACH_PARENT_PROCESS = -1;
    
            [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
            static extern bool AllocConsole();
    
            [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
            static extern bool FreeConsole();
    
            /// <summary>
            /// アプリケーションのメイン エントリ ポイントです。
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
          //引数でGUIorCUIを切り替えたい if (args[0] == "GUI") { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else { var attachConsole = AttachConsole(ATTACH_PARENT_PROCESS); if (attachConsole == false) { // 親のコンソールがないので作成する if (AllocConsole() == false) { return; } //// 標準出力のストリームを取得(ここらへんが間違ってると思います) var stream = Console.OpenStandardOutput(); var stdout = new StreamWriter(stream) { // Write メソッド実行時に即出力するためには AutoFlush プロパティを True にする必要があるらしい AutoFlush = true, }; //// 出力先を標準出力に設定 Console.SetOut(stdout); } Console.WriteLine("Hello World."); Console.WriteLine("続行するには何かキーを押してください"); Console.ReadKey(); if (attachConsole == false) { // コンソールの解放 FreeConsole(); } } } } }

    何かいい設定方法がないでしょうかお教え願います。






    • 編集済み fushy 2019年5月27日 3:05
    2019年5月27日 1:25

回答

  • デバックコンソールのほうに”Hello World.”が表示されてしまいます。

    デバッ ⇒ デバッというのはさておき。

    とりあえず、こんな感じで切り替えられました。
    ただし Console.IsOutputRedirected は true のままですし、Console.ForegroundColor も機能しません…。
    (Visual Studio 上からのデバッグ実行でない場合は、ForegroundColor も変化します)

    using Microsoft.Win32.SafeHandles;
    using System;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace ConsoleGUI
    {
        static class Program
        {
            [DllImport("Kernel32.dll")]
            static extern bool AttachConsole(int processId);
            const int ATTACH_PARENT_PROCESS = -1;
    
            [DllImport("Kernel32.dll")]
            static extern bool AllocConsole();
            [DllImport("Kernel32.dll")]
            static extern bool FreeConsole();
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr CreateFileW(
                  string lpFileName,
                  uint dwDesiredAccess,
                  uint dwShareMode,
                  IntPtr lpSecurityAttributes,
                  uint dwCreationDisposition,
                  uint dwFlagsAndAttributes,
                  IntPtr hTemplateFile
            );
            const uint GENERIC_WRITE = 0x40000000;
            const uint GENERIC_READ = 0x80000000;
            const uint OPEN_EXISTING = 0x00000003;
            const uint FILE_SHARE_WRITE = 0x2;
            const int STD_INPUT_HANDLE = -10;
            const int STD_OUTPUT_HANDLE = -11;
            const int STD_ERROR_HANDLE = -12;
            [DllImport("kernel32.dll")]
            static extern bool SetStdHandle(int nStdHandle, SafeFileHandle handle);
            // [DllImport("kernel32.dll")]
            // static extern IntPtr GetStdHandle(int nStdHandle);
            // [DllImport("kernel32.dll")]
            // static extern bool GetConsoleMode(SafeFileHandle hConsoleHandle, out uint lpMode);
            // [DllImport("kernel32.dll")]
            // static extern bool SetConsoleMode(SafeFileHandle hConsoleHandle, uint dwMode);
            // const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 0x200;
    
            [STAThread]
            static void Main(string[] args)
            {
                // if (args[0] == "GUI")
                if (args?.FirstOrDefault() == "GUI")
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
                else
                {
                    var attachConsole = AttachConsole(ATTACH_PARENT_PROCESS);
                    if (!attachConsole)
                    {
                        // 親のコンソールがないので作成する
                        if (!AllocConsole())
                        {
                            return;
                        }
                        var outFile = CreateFileW("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
                        var safeHandle = new SafeFileHandle(outFile, true);
                        SetStdHandle(STD_OUTPUT_HANDLE, safeHandle);
                        var fs = new FileStream(safeHandle, FileAccess.Write);
                        var writer = new StreamWriter(fs, Console.OutputEncoding) { AutoFlush = true };
                        Console.SetOut(writer);
                    }
                    Console.ForegroundColor = ConsoleColor.Blue;    // 効かない…
                    Console.WriteLine("Hello World.");
    
                    Console.WriteLine("続行するには何かキーを押してください");
                    Console.ReadKey();
                    if (!attachConsole)
                    {
                        FreeConsole();
                    }
                }
            }
        }
    }
    2019年5月27日 7:05
  • 先のコードに加えて、下記の修正を行ってみてください。

    var outFile = CreateFileW("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

    当方環境ではこれにより、Console.IsOutputRedirected が false に戻り、Console.ForegroundColor や Console.WindowWidth も使用可能な状態に復元しました。

    • 回答としてマーク fushy 2019年5月28日 1:03
    • 回答としてマークされていない fushy 2019年5月28日 1:09
    • 回答としてマーク fushy 2019年5月28日 1:09
    2019年5月27日 9:05

すべての返信

  • デバックコンソールのほうに”Hello World.”が表示されてしまいます。

    デバッ ⇒ デバッというのはさておき。

    とりあえず、こんな感じで切り替えられました。
    ただし Console.IsOutputRedirected は true のままですし、Console.ForegroundColor も機能しません…。
    (Visual Studio 上からのデバッグ実行でない場合は、ForegroundColor も変化します)

    using Microsoft.Win32.SafeHandles;
    using System;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace ConsoleGUI
    {
        static class Program
        {
            [DllImport("Kernel32.dll")]
            static extern bool AttachConsole(int processId);
            const int ATTACH_PARENT_PROCESS = -1;
    
            [DllImport("Kernel32.dll")]
            static extern bool AllocConsole();
            [DllImport("Kernel32.dll")]
            static extern bool FreeConsole();
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr CreateFileW(
                  string lpFileName,
                  uint dwDesiredAccess,
                  uint dwShareMode,
                  IntPtr lpSecurityAttributes,
                  uint dwCreationDisposition,
                  uint dwFlagsAndAttributes,
                  IntPtr hTemplateFile
            );
            const uint GENERIC_WRITE = 0x40000000;
            const uint GENERIC_READ = 0x80000000;
            const uint OPEN_EXISTING = 0x00000003;
            const uint FILE_SHARE_WRITE = 0x2;
            const int STD_INPUT_HANDLE = -10;
            const int STD_OUTPUT_HANDLE = -11;
            const int STD_ERROR_HANDLE = -12;
            [DllImport("kernel32.dll")]
            static extern bool SetStdHandle(int nStdHandle, SafeFileHandle handle);
            // [DllImport("kernel32.dll")]
            // static extern IntPtr GetStdHandle(int nStdHandle);
            // [DllImport("kernel32.dll")]
            // static extern bool GetConsoleMode(SafeFileHandle hConsoleHandle, out uint lpMode);
            // [DllImport("kernel32.dll")]
            // static extern bool SetConsoleMode(SafeFileHandle hConsoleHandle, uint dwMode);
            // const uint ENABLE_VIRTUAL_TERMINAL_INPUT = 0x200;
    
            [STAThread]
            static void Main(string[] args)
            {
                // if (args[0] == "GUI")
                if (args?.FirstOrDefault() == "GUI")
                {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
                else
                {
                    var attachConsole = AttachConsole(ATTACH_PARENT_PROCESS);
                    if (!attachConsole)
                    {
                        // 親のコンソールがないので作成する
                        if (!AllocConsole())
                        {
                            return;
                        }
                        var outFile = CreateFileW("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
                        var safeHandle = new SafeFileHandle(outFile, true);
                        SetStdHandle(STD_OUTPUT_HANDLE, safeHandle);
                        var fs = new FileStream(safeHandle, FileAccess.Write);
                        var writer = new StreamWriter(fs, Console.OutputEncoding) { AutoFlush = true };
                        Console.SetOut(writer);
                    }
                    Console.ForegroundColor = ConsoleColor.Blue;    // 効かない…
                    Console.WriteLine("Hello World.");
    
                    Console.WriteLine("続行するには何かキーを押してください");
                    Console.ReadKey();
                    if (!attachConsole)
                    {
                        FreeConsole();
                    }
                }
            }
        }
    }
    2019年5月27日 7:05
  • 先のコードに加えて、下記の修正を行ってみてください。

    var outFile = CreateFileW("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

    当方環境ではこれにより、Console.IsOutputRedirected が false に戻り、Console.ForegroundColor や Console.WindowWidth も使用可能な状態に復元しました。

    • 回答としてマーク fushy 2019年5月28日 1:03
    • 回答としてマークされていない fushy 2019年5月28日 1:09
    • 回答としてマーク fushy 2019年5月28日 1:09
    2019年5月27日 9:05
  • ありがとうございます。無事行いたいことができるようになりました。

    これでデバッ作業もはかどります。
    (恥ずかしい限りです・・・/////

    if(args?.FirstOrDefault()=="GUI")

    の指摘もありがとうございました。これなら例外を出さずに済みます。






    • 編集済み fushy 2019年5月28日 1:15
    2019年5月28日 1:13