From 7763c98188de44bca1136712ce40b60e031496bd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Jun 2017 08:39:34 -0700 Subject: [PATCH] wincolor: Re-fetch the console on all calls The primary motivation for this commit was rust-lang/cargo#4189 where dropping a `wincolor::Console` would call `CloseHandle` to close the console handle. Cargo creates a few `Console` instances so it ended up closing stdout a little earlier as intended! The `GetStdHandle` function returns handles I believe aren't intended to be closed (as there's no refcounting). I believe libstd doesn't close these handles. This commit also moves to calling `GetStdHandle` on demand which libstd changed to doing so recently as well, preventing caching of stale handles that change over time with calls to `SetStdHandle`. --- wincolor/src/win.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/wincolor/src/win.rs b/wincolor/src/win.rs index e61240b..c0ad835 100644 --- a/wincolor/src/win.rs +++ b/wincolor/src/win.rs @@ -2,7 +2,7 @@ use std::io; use std::mem; use kernel32; -use winapi::{DWORD, HANDLE, WORD}; +use winapi::{DWORD, WORD}; use winapi::winbase::{STD_ERROR_HANDLE, STD_OUTPUT_HANDLE}; use winapi::wincon::{ FOREGROUND_BLUE as FG_BLUE, @@ -30,33 +30,25 @@ const FG_WHITE: DWORD = FG_BLUE | FG_GREEN | FG_RED; /// stdout before setting new text attributes. #[derive(Debug)] pub struct Console { - handle: HANDLE, + handle_id: DWORD, start_attr: TextAttributes, cur_attr: TextAttributes, } -unsafe impl Send for Console {} - -impl Drop for Console { - fn drop(&mut self) { - unsafe { kernel32::CloseHandle(self.handle); } - } -} - impl Console { /// Get a console for a standard I/O stream. fn create_for_stream(handle_id: DWORD) -> io::Result { let mut info = unsafe { mem::zeroed() }; - let (handle, res) = unsafe { + let res = unsafe { let handle = kernel32::GetStdHandle(handle_id); - (handle, kernel32::GetConsoleScreenBufferInfo(handle, &mut info)) + kernel32::GetConsoleScreenBufferInfo(handle, &mut info) }; if res == 0 { return Err(io::Error::last_os_error()); } let attr = TextAttributes::from_word(info.wAttributes); Ok(Console { - handle: handle, + handle_id: handle_id, start_attr: attr, cur_attr: attr, }) @@ -80,7 +72,8 @@ impl Console { fn set(&mut self) -> io::Result<()> { let attr = self.cur_attr.to_word(); let res = unsafe { - kernel32::SetConsoleTextAttribute(self.handle, attr) + let handle = kernel32::GetStdHandle(self.handle_id); + kernel32::SetConsoleTextAttribute(handle, attr) }; if res == 0 { return Err(io::Error::last_os_error());