9

.NETFramework4.0で実行されるWinFormsアプリケーションを作成しました。Console.WriteLine()Win32 API関数を呼び出した後(一度、起動時に)、メソッドを使用して親コンソールに書き込みますAttachConsole(-1)

画面に出力を表示するだけで問題なく動作します。残念ながら、次のようなパイプリダイレクト演算子を使用してバッチを使用すると、次のようになります。

application.exe > output.txt

空のファイルを作成するだけです。たぶん、私が使用するときに対処されている実際のパイプに関連するいくつかの問題がありますAttachConsoleか?コマンドプロンプトがデータをキャッチしてファイルに配置できないのはなぜですか?そのようなシナリオに関連する問題について誰かが知っていますか?

4

1 に答える 1

15

Console.Out遅延して初期化されます。初めてそれを参照するとGetStdHandle(STD_OUTPUT_HANDLE)、標準出力ハンドルを取得するためにランタイムが呼び出されます。この呼び出しが呼び出しの前に発生した場合AttachConsole、リダイレクト用のファイルへのハンドルを取得します。この呼び出しが後で発生すると、コンソール出力ハンドルを取得します。

次のクラスは、標準出力とエラー ハンドルを修正します。コンソールからアプリケーションを起動すると、次のプロンプトの後に出力が表示されることに気付くでしょう。で回避できますstart /wait

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));
        }
    }
}
于 2012-07-17T15:46:08.693 に答える