9

我制作了一个在 .NET Framework 4.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 回答