c# - CONSOLE_SCREEN_BUFFER_INFOEX 无效;GetConsoleScreenBufferInfoEx (kernel32)
问题描述
GetConsoleScreenBufferInfoEx 无效返回值
我正在尝试更改控制台的调色板。为了完成这件事,我首先需要Get
我的ConsoleScreenBufferInfoEx
,然后Set
是它。问题是我什至无法ConsoleScreenBufferInfoEx
从STD_OUTPUT_HANDLE
. 下面的代码抛出此错误消息:
System.ArgumentException: 'Value does not fall in the expected range.'
句柄有效,但我收到此错误。我已经对每种数据类型和相关的 pinvoke 条目进行了四次检查——一切对我来说都很好。没有示例代码,GetConsoleScreenBufferInfoEx
我还没有找到可行的解决方案。
我的消息来源:
示例应用程序 (.NET Core 3.1):
要使此代码正常工作,项目的构建属性必须允许不安全的代码。
[属性 -> 构建 -> 允许不安全代码]
using Microsoft.Win32.SafeHandles;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace ScreenBufferInfoExample
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeFileHandle GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool GetConsoleScreenBufferInfoEx(SafeFileHandle hConsoleOutput,
out CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfo);
static void Main()
{
SafeFileHandle stdOut = GetStdHandle(-11);
if(stdOut.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
CONSOLE_SCREEN_BUFFER_INFO_EX info = new CONSOLE_SCREEN_BUFFER_INFO_EX();
info.cbSize = (uint)Marshal.SizeOf(info);
if(!GetConsoleScreenBufferInfoEx(stdOut, out info)) {
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());// <- this gets thrown
// System.ArgumentException: 'Value does not fall within the expected range.'
}
Console.ReadKey(true);
}
}
[StructLayout(LayoutKind.Sequential)]
struct CONSOLE_SCREEN_BUFFER_INFO_EX
{
public uint cbSize;
public COORD dwSize;
public COORD dwCursorPosition;
public ushort wAttributes;
public SMALL_RECT srWindow;
public COORD dwMaximumWindowSize;
public ushort wPopupAttributes;
public bool bFullscreenSupported;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public COLORREF[] ColorTable;
}
[StructLayout(LayoutKind.Sequential)]
struct COORD
{
public short X;
public short Y;
}
[StructLayout(LayoutKind.Sequential)]
struct SMALL_RECT
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct COLORREF
{
public uint ColorDWORD;
public COLORREF(int r, int g, int b)
: this(Color.FromArgb(r, g, b)) { }
public COLORREF(Color color)
{
ColorDWORD = (uint)color.R
+ (((uint)color.G) << 8)
+ (((uint)color.B) << 16);
}
public Color GetColor()
{
return Color.FromArgb((int)(0x000000FFU & ColorDWORD),
(int)(0x0000FF00U & ColorDWORD) >> 8,
(int)(0x00FF0000U & ColorDWORD) >> 16);
}
public void SetColor(Color color)
{
ColorDWORD = (uint)color.R
+ (((uint)color.G) << 8)
+ (((uint)color.B) << 16);
}
}
}
解决方案
pinvoke.net 通常很有用,但并不总是正确的。
由于需要将信息传入传出 GetConsoleScreenBufferInfoEx 方法,因此参数不能为out
,但必须为ref
。
所以正确的声明是
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool GetConsoleScreenBufferInfoEx(SafeFileHandle hConsoleOutput,
ref CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfo);
称为GetConsoleScreenBufferInfoEx(stdOut, ref info)
.
(我刚刚相应地更正了 pinvoke.net 上的页面)
推荐阅读
- python - 我将如何将此代码编写为“try-except”块而不是多个 if 块?
- domain-driven-design - 事件源或 CQRS 应用程序的读取端是否也应该返回 AggregateRoots?
- python - 为什么我的 python 打印运行速度比 Go 的 fmt.Print 和 os.Stdout.Write 快
- javascript - 将脚本附加并执行到 HTML
- .net-core - 使用模式使用 dotnet test 测试多个项目
- javascript - vue,通过 v-model 绑定来自所选选项的两个值
- r - R:如何使用 if 或 for 来获得循环?
- php - 从 TikTok 抓取数据?
- r - 使用 rowsum 或 rowSums 进行子集化
- php - Laravel Cashier 不完整的 3D Secure / SCA 异常处理