c# - 调用 System.Console.WindowWidth 时出现 System.IO.IOException

标签 c# console console-application psexec

<分区>

当调用 System.Console.BufferWidthSystem.Console.CurserLeftSystem.Console.WindowWidth 中的任何一个时,我是从 PsExec 中执行我的 [console] 应用程序时遇到 System.IO.IOException。 在标准命令窗口中执行时,一切正常。

非常感谢任何建议。

最佳答案

还有 budda-bing budda-boom,我发现了一个解决方案!

事实证明,PsExec 有一个 native 函数作为其输入属性之一,称为 <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171%28v=vs.85%29.aspx" rel="noreferrer noopener nofollow">GetConsoleScreenBufferInfo</a>

此 native 函数可通过 P/Invoke 调用,并可用于在 .NET API 无法访问控制台对象的情况下获取任何非标准控制台屏幕缓冲区属性。

我用过的代码如下:

static void Main(string[] args)
{
    // ... other code and stuff
    int windowWidth;
    if (!ConsoleEx.GetConsoleWindowWidth(out windowWidth))
        windowWidth = Int32.MaxValue; // if no console, no limits
    // ... other code and stuff
}

internal static class ConsoleEx
{
    /// <summary>
    /// Contains information about a console screen buffer.
    /// </summary>
    private struct ConsoleScreenBufferInfo
    {
        /// <summary> A CoOrd structure that contains the size of the console screen buffer, in character columns and rows. </summary>
        internal CoOrd dwSize;
        /// <summary> A CoOrd structure that contains the column and row coordinates of the cursor in the console screen buffer. </summary>
        internal CoOrd dwCursorPosition;
        /// <summary> The attributes of the characters written to a screen buffer by the WriteFile and WriteConsole functions, or echoed to a screen buffer by the ReadFile and ReadConsole functions. </summary>
        internal Int16 wAttributes;
        /// <summary> A SmallRect structure that contains the console screen buffer coordinates of the upper-left and lower-right corners of the display window. </summary>
        internal SmallRect srWindow;
        /// <summary> A CoOrd structure that contains the maximum size of the console window, in character columns and rows, given the current screen buffer size and font and the screen size. </summary>
        internal CoOrd dwMaximumWindowSize;
    }

    /// <summary>
    /// Defines the coordinates of a character cell in a console screen buffer. 
    /// The origin of the coordinate system (0,0) is at the top, left cell of the buffer.
    /// </summary>
    private struct CoOrd
    {
        /// <summary> The horizontal coordinate or column value. </summary>
        internal Int16 X;
        /// <summary> The vertical coordinate or row value. </summary>
        internal Int16 Y;
    }

    /// <summary>
    /// Defines file type values for use when retrieving the type of a specified file.
    /// </summary>
    private enum FileType
    {
        /// <summary> Either the type of the specified file is unknown, or the function failed. </summary>
        Unknown,
        /// <summary> The specified file is a disk file. </summary>
        Disk,
        /// <summary> The specified file is a character file, typically an LPT device or a console. </summary>
        Char,
        /// <summary> The specified file is a socket, a named pipe, or an anonymous pipe. </summary>
        Pipe
    };

    /// <summary>
    /// Gets a value that indicates whether the error output stream has been redirected from the standard error stream.
    /// </summary>
    internal static Boolean IsErrorRedirected
    {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.StdErr)); }
    }

    /// <summary>
    /// Gets a value that indicates whether input has been redirected from the standard input stream.
    /// </summary>
    internal static Boolean IsInputRedirected
    {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.StdIn)); }
    }

    /// <summary>
    /// Gets a value that indicates whether output has been redirected from the standard output stream.
    /// </summary>
    internal static Boolean IsOutputRedirected
    {
        get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.StdOut)); }
    }

    /// <summary>
    /// Gets the column position of the cursor within the buffer area.
    /// </summary>
    /// <param name="returnLeftIfNone">
    /// In the event that there is no console, the value passed here will be the return value
    /// </param>
    /// <returns>
    /// The current position, in columns, of the cursor
    /// </returns>
    internal static Int32 GetConsoleCursorLeft(Int32 returnLeftIfNone = 0)
    {
        if (!IsOutputRedirected) // if the output is not being redirected
            return Console.CursorLeft; // return the current cursor [left] position
        else
        { // try and get the Console Buffer details
            ConsoleScreenBufferInfo csbi;
            if (GetConsoleScreenBufferInfo(GetStdHandle(StdHandle.StdOut), out csbi)) // if the console buffer exists
                return csbi.dwCursorPosition.X; // return the cursor [left] position
        }

        return returnLeftIfNone; // no console; return the desired position in this event
    }

    /// <summary>
    /// Gets the console screen buffer window height.
    /// </summary>
    /// <param name="windowHeight">
    /// A System.Int32 property that will receive the console screen buffer height
    /// </param>
    /// <returns>
    /// Returns a System.Boolean value of true if a console screen exists and the height retrieved; else false
    /// </returns>
    internal static Boolean GetConsoleWindowHeight(out Int32 windowHeight)
    {
        int discardWidth;
        return GetConsoleWindowSize(out windowHeight, out discardWidth);
    }

    /// <summary>
    /// Gets the console screen buffer window size.
    /// </summary>
    /// <param name="windowHeight">
    /// A System.Int32 property that will receive the console screen buffer height
    /// </param>
    /// <param name="windowWidth">
    /// A System.Int32 property that will receive the console screen buffer width
    /// </param>
    /// <returns>
    /// Returns a System.Boolean value of true if a console screen exists and the information retrieved; else false
    /// </returns>
    internal static Boolean GetConsoleWindowSize(out Int32 windowHeight, out Int32 windowWidth)
    {
        windowHeight = 0;
        windowWidth = 0;

        if (!IsOutputRedirected)
        { // if the output is not being redirected
            windowHeight = Console.WindowHeight; // out the current console window height
            windowWidth = Console.WindowWidth; // out the current console window width
            return true;
        }
        else
        { // try and get the Console Buffer details
            ConsoleScreenBufferInfo csbi;
            if (GetConsoleScreenBufferInfo(GetStdHandle(StdHandle.StdOut), out csbi))
            { // if the console buffer exists
                windowHeight = csbi.dwSize.Y; // out the current console window height
                windowWidth = csbi.dwSize.X; // out the current console window width
                return true;
            }
        }

        return false; // no console
    }

    /// <summary>
    /// Gets the console screen buffer window height.
    /// </summary>
    /// <param name="windowWidth">
    /// A System.Int32 property that will receive the console screen buffer width
    /// </param>
    /// <returns>
    /// Returns a System.Boolean value of true if a console screen exists and the width retrieved; else false
    /// </returns>
    internal static Boolean GetConsoleWindowWidth(out Int32 windowWidth)
    {
        int discardHeight;
        return GetConsoleWindowSize(out discardHeight, out windowWidth);
    }

    /// <summary>
    /// Retrieves information about the specified console screen buffer.
    /// </summary>
    /// <param name="hConsoleOutput">
    /// A handle to the console screen buffer
    /// </param>
    /// <param name="lpConsoleScreenBufferInfo">
    /// A pointer to a ConsoleScreenBufferInfo structure that receives the console screen buffer information
    /// </param>
    /// <returns>
    /// If the information retrieval succeeds, the return value is nonzero; else the return value is zero
    /// </returns>
    [DllImport("kernel32.dll")]
    private static extern Boolean GetConsoleScreenBufferInfo(
        IntPtr hConsoleOutput,
        out ConsoleScreenBufferInfo lpConsoleScreenBufferInfo);

    /// <summary>
    /// Retrieves the file type of the specified file.
    /// </summary>
    /// <param name="hFile">
    /// A handle to the file
    /// </param>
    /// <returns>
    /// Returns one of the FileType enum values
    /// </returns>
    [DllImport("kernel32.dll")]
    private static extern FileType GetFileType(IntPtr hFile);

    /// <summary>
    /// Retrieves a handle to the specified standard device (standard input, standard output, or standard error).
    /// </summary>
    /// <param name="nStdHandle">
    /// The standard device
    /// </param>
    /// <returns>
    /// Returns a value that is a handle to the specified device, or a redirected handle
    /// </returns>
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetStdHandle(StdHandle nStdHandle);

    /// <summary>
    /// Defines the coordinates of the upper left and lower right corners of a rectangle.
    /// </summary>
    private struct SmallRect
    {
        /// <summary> The x-coordinate of the upper left corner of the rectangle. </summary>
        internal Int16 Left;
        /// <summary> The y-coordinate of the upper left corner of the rectangle. </summary>
        internal Int16 Top;
        /// <summary> The x-coordinate of the lower right corner of the rectangle. </summary>
        internal Int16 Right;
        /// <summary> The y-coordinate of the lower right corner of the rectangle. </summary>
        internal Int16 Bottom;
    }

    /// <summary>
    /// Defines the handle type of a standard device.
    /// </summary>
    private enum StdHandle
    {
        /// <summary> The standard input device. Initially, this is the console input buffer, CONIN$. </summary>
        StdIn = -10,
        /// <summary> The standard output device. Initially, this is the active console screen buffer, CONOUT$. </summary>
        StdOut = -11,
        /// <summary> The standard error device. Initially, this is the active console screen buffer, CONOUT$. </summary>
        StdErr = -12
    };

    /// <summary>
    /// Writes the specified string value to the standard output stream.
    /// </summary>
    /// <param name="value">
    /// The value to write
    /// </param>
    /// <param name="valueLength">
    /// The length of the last line written from value
    /// </param>
    internal static void Write(String value, out Int32 valueLength)
    {
        string[] valueArray = value.Split(new char[] { '\r', '\n' }); // split the value by either carriage returns or a line feeds
        valueLength = valueArray[valueArray.Count() - 1].Length; // out the length of the last line

        Console.Write(value); // write the value to the output stream
    }
}

...而且我很高兴地确认这在 native 控制台窗口、PsExec 或重定向到文件时都能很好地工作。

我希望其他人可以利用这个:D

关于c# - 调用 System.Console.WindowWidth 时出现 System.IO.IOException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20492535/

相关文章:

c# - 在 C# 中, "symbol"究竟被归类为什么?

c# - 如果在 C# 中失败,则回滚 sql 事务

c# - 如何获取 Sql Server 数据库中所有模式的列表

linux - 如何将日志文件重定向(管道)到控制台?

c# - 在控制台应用程序中以编程方式动态创建和导出 WPF Viewport3D 视觉对象

c# - 在C#中写行错误

c# - 如何在 C# 中转换或编写此 Javascript 数组

c# - 如何基于属性使用 JSON.NET 序列化枚举?

c++ - 是否可以通过标准 C++ IOStream 在 Shell 中显示可编辑文本?

c# - .Net 控制台应用程序在后台运行