1
//! Helper functions for handling the Windows console from a GUI context.
2
//!
3
//! Windows subsystem applications must explicitly attach to an existing console
4
//! before stdio works, and if not available, create their own if they wish to
5
//! print anything.
6
//!
7
//! These functions enable that, primarily for the purposes of displaying Rust
8
//! panics.
9

            
10
use std::error::Error;
11
use std::result::Result;
12

            
13
#[cfg(windows)]
14
use winapi::um::consoleapi::AllocConsole;
15

            
16
#[cfg(windows)]
17
use winapi::um::wincon::AttachConsole;
18
#[cfg(windows)]
19
use winapi::um::wincon::FreeConsole;
20
#[cfg(windows)]
21
use winapi::um::wincon::GetConsoleWindow;
22
#[cfg(windows)]
23
use winapi::um::wincon::ATTACH_PARENT_PROCESS;
24

            
25
pub struct Console {
26
    #[cfg(windows)]
27
    attached: bool,
28
}
29

            
30
/// Initialises the console. On Windows this either attaches to the
31
pub fn init() -> Result<Console, Box<dyn Error>> {
32
    #[cfg(windows)]
33
    unsafe {
34
        // Check if we're attached to an existing Windows console
35
        if GetConsoleWindow().is_null() {
36
            // Try to attach to an existing Windows console.
37
            //
38
            // It's normally a no-brainer to call this - it just makes println! and friends
39
            // work as expected, without cluttering the screen with a console in the general
40
            // case.
41
            if AttachConsole(ATTACH_PARENT_PROCESS) == 0 {
42
                // Try to attach to a console, and if not, allocate ourselves a new one.
43
                if AllocConsole() != 0 {
44
                    Ok(Console { attached: false })
45
                } else {
46
                    Err("Failed to attach to a console, and to create one".into())
47
                }
48
            } else {
49
                // We attached to an existing console.
50
                Ok(Console { attached: true })
51
            }
52
        } else {
53
            // The program was started with a console attached.
54
            Ok(Console { attached: true })
55
        }
56
    }
57

            
58
    #[cfg(not(windows))]
59
    {
60
        Ok(Console {})
61
    }
62
}
63

            
64
impl Drop for Console {
65
    fn drop(&mut self) {
66
        // Free the allocated console, when it was not attached.
67
        #[cfg(windows)]
68
        if !self.attached {
69
            unsafe { FreeConsole() };
70
        }
71
    }
72
}