Winapi 如何仅使用标准库写入Windows上的备用屏幕缓冲区?

Winapi 如何仅使用标准库写入Windows上的备用屏幕缓冲区?,winapi,rust,output,buffer,handle,Winapi,Rust,Output,Buffer,Handle,我正在为我的跨平台终端操作板条箱开发一个备用屏幕功能 形势 当我想写一些东西到控制台时,我可以使用下面的代码来写到当前控制台。这适用于UNIX和Windows系统: write!(::std::fmt::io::stdout(), "Some text"). 当我切换到备用屏幕时,我不想写入当前屏幕,而是写入备用屏幕。这取决于您所处的平台不同。基本原理是一样的:我需要将句柄全局存储在某个位置,以便将存储的输出句柄置于交替屏幕模式,并将所有输出、命令和操作写入存储的输出句柄 当我处于备用模式时,

我正在为我的跨平台终端操作板条箱开发一个备用屏幕功能

形势

当我想写一些东西到控制台时,我可以使用下面的代码来写到当前控制台。这适用于UNIX和Windows系统:

write!(::std::fmt::io::stdout(), "Some text").
当我切换到备用屏幕时,我不想写入当前屏幕,而是写入备用屏幕。这取决于您所处的平台不同。基本原理是一样的:我需要将句柄全局存储在某个位置,以便将存储的
输出句柄
置于交替屏幕模式,并将所有输出、命令和操作写入存储的
输出句柄

当我处于备用模式时,我的代码会写入备用屏幕,当我处于主屏幕模式时,我的代码会写入主屏幕

  • Unix

    对于UNIX系统,我可以使用切换到。我将
    ::std::io::stdout()
    存储在某个地方,所有UNIX代码都使用该句柄访问终端
    输出。在交替屏幕模式下,我所做的所有
    写入操作都在交替屏幕上完成,而在主屏幕上,所有
    写入操作都在主屏幕上完成

  • 窗户

    对于Windows系统,我可以使用。我将使用创建一个新的屏幕缓冲区,然后使用它来更改活动缓冲区。最后,我需要存储从
    CreateConsoleScreenBuffer
    获取的句柄。通过这个输出句柄,我可以将输出写入备用屏幕缓冲区

如果我不使用上述方式,切换到备用屏幕,只调用这个
write!(::std::fmt::io::stdout(),“一些文本”)
,在Windows和Unix系统上,我会写入主屏幕而不是备用屏幕,因为
stdout()

问题

上述方法在一定程度上起作用;当我想写入存储的句柄时

对于Unix,我可以执行以下操作:

// (...) some logic to get the handle to the current screen.
let stored_handle: Write = ...;
write!(stored_handle, "Some text);
#[cfg(target_os = "windows")]
let storage = WindowsScreenManager::new();
#[cfg(not(target_os = "windows"))]
let storage = UnixScreenManager::new();

write!(storage, "Some text");
但对于Windows,我可以这样做:

// (...) some logic to get the handle to the current screen for windows.
let stored_handle: HANDLE = ...;
write!(stored_handle, "Some text);
我可以为存储
stdout
的结构实现
std::io::Write
,以便为Windows创建自己的逻辑,用WinAPI向控制台写入。如果我这样做,我将能够像下面那样写入该结构:

// (...) some logic to get the handle to the current screen.
let stored_handle: Write = ...;
write!(stored_handle, "Some text);
#[cfg(target_os = "windows")]
let storage = WindowsScreenManager::new();
#[cfg(not(target_os = "windows"))]
let storage = UnixScreenManager::new();

write!(storage, "Some text");
这对我的情况并不理想,因为我不能使用像
\n\t
这样的生锈字符串转义字符。这样做时,我的字符串将不包含任何换行符或制表符。考虑一下,因为WinAPI不知道这些格式化选项。此外,我不想在我这方面手动管理所有写入Windows控制台的操作

我真的想把WinAPI
句柄
用作
std::io::Write
,这样它就可以在
写操作中使用了宏,就像我在UNIX中所做的那样。只需存储
stdout()
并使用
write
宏,但存储
句柄
并写入该句柄

我想这应该可以在调用
println!()
写!(stdout())
在Windows上,它将向当前进程的标准输出句柄写入。但是现在我想写入备用句柄,而不仅仅是默认句柄。还是我错了


如果无法完成上述操作,我将如何写入备用屏幕
句柄
,而不使用自己的实现来使用WinAPI写入控制台?

在编译时替换字符串中的转义,如
\n
\t
。你到底有什么问题?如果我使用它们,我会在控制台中看到一些奇怪的符号。可能是因为在使用
WriteConsoleOutputCharacterA
将其写入控制台之前,我将其编码为utf16(这需要完成)。另外,它增加了我使用WinAPI处理所有控制台写入操作的复杂性。IIRC
WriteConsoleOutputCharacterA
用于ANSI字符串。如果用UTF-16(UniCode)编码字符串,则正确的函数是。结果仍然相同,反斜杠仍然显示为符号。如果用
value.encode\u utf16().collect()替换
win32\u字符串的主体,是否也一样?我不认为
encode\u-wide
实际上是从UTF-8到UTF-16的转码
OsStr
可以是任意字节。