Skip to content

Commit eed58d0

Browse files
committed
Add a custom panic handler, opening a console if needed
1 parent a955e26 commit eed58d0

File tree

4 files changed

+95
-15
lines changed

4 files changed

+95
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "compactor"
33
version = "0.7.0"
44
authors = ["Thomas Hurst <[email protected]>"]
5+
homepage = "https://github.com/Freaky/Compactor"
56
description = "An interface to Windows 10 filesystem compression"
67
edition = "2018"
78
license = "MIT"
@@ -27,6 +28,7 @@ siphasher = "0.3.0"
2728
walkdir = "2.2.8"
2829
web-view = { path = "../web-view/" }
2930
winapi = { version = "0.3.7", features = [ "combaseapi", "ioapiset", "knownfolders", "shellscalingapi", "shlobj", "shtypes", "winbase", "winerror", "winioctl", "winver"] }
31+
backtrace = "0.3.32"
3032

3133
[[bin]]
3234
name = "Compactor"
@@ -39,6 +41,7 @@ winres = "0.1"
3941
[profile.release]
4042
opt-level = "s"
4143
lto = true
44+
codegen-units = 1
4245
debug = false
4346

4447
[dev-dependencies]

src/console.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
// Helper functions for handling the Windows console from a GUI context.
3+
//
4+
// Windows subsystem applications must explicitly attach to an existing console
5+
// before stdio works, and if not available, create their own if they wish to
6+
// print anything.
7+
//
8+
// These functions enable that, primarily for the purposes of displaying Rust
9+
// panics.
10+
11+
use winapi::um::consoleapi::{AllocConsole};
12+
use winapi::um::wincon::{AttachConsole, FreeConsole, GetConsoleWindow, ATTACH_PARENT_PROCESS};
13+
14+
/// Check if we're attached to an existing Windows console
15+
pub fn is_attached() -> bool {
16+
unsafe {
17+
!GetConsoleWindow().is_null()
18+
}
19+
}
20+
21+
/// Try to attach to an existing Windows console, if necessary.
22+
///
23+
/// It's normally a no-brainer to call this - it just makes println! and friends
24+
/// work as expected, without cluttering the screen with a console in the general
25+
/// case.
26+
pub fn attach() -> bool {
27+
if is_attached() {
28+
return true;
29+
}
30+
31+
unsafe { AttachConsole(ATTACH_PARENT_PROCESS) != 0 }
32+
}
33+
34+
/// Try to attach to a console, and if not, allocate ourselves a new one.
35+
pub fn alloc() -> bool {
36+
if attach() {
37+
return true;
38+
}
39+
40+
unsafe { AllocConsole() != 0 }
41+
}
42+
43+
/// Free any allocated console, if any.
44+
pub fn free() {
45+
unsafe { FreeConsole() };
46+
}

src/main.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,61 @@
33

44
mod backend;
55
mod background;
6+
mod console;
67
mod compact;
78
mod compression;
89
mod config;
910
mod folder;
1011
mod gui;
1112
mod persistence;
1213

13-
use winapi::um::wincon::{AttachConsole, FreeConsole, ATTACH_PARENT_PROCESS};
14+
fn setup_panic() {
15+
std::panic::set_hook(Box::new(|e| {
16+
if !console::alloc() {
17+
// No point trying to print without a console...
18+
return;
19+
}
1420

15-
fn main() {
16-
let mut rc = 0;
21+
println!(r#"
22+
Oh dear, {app} has crashed. Sorry :(
1723
18-
// Enable console printing with Windows subsystem
19-
unsafe {
20-
AttachConsole(ATTACH_PARENT_PROCESS);
21-
}
24+
You can report this on the website at {website}/issues
2225
23-
if let Err(e) = std::panic::catch_unwind(gui::spawn_gui) {
24-
eprintln!("Unhandled panic: {:?}", e);
25-
rc = 1;
26-
}
26+
Please try to include everything below the line, and give some hints as to what
27+
you were doing - like what folder you were running it on.
2728
28-
unsafe {
29-
FreeConsole();
30-
}
29+
#############################################################################
30+
31+
App: {app}, Version: {ver}, Build Date: {date}, Hash: {hash}
32+
"#, app = env!("CARGO_PKG_NAME"), website = env!("CARGO_PKG_HOMEPAGE"),
33+
ver = env!("VERGEN_SEMVER"), date = env!("VERGEN_BUILD_DATE").to_string(), hash = env!("VERGEN_SHA_SHORT"));
34+
35+
if let Some(s) = e.payload().downcast_ref::<&'static str>() {
36+
println!("panic: {}", s);
37+
} else {
38+
println!("panic: [mysteriously lacks a string representation]");
39+
}
40+
41+
println!("\nHit Enter to print the rest of the debug info.");
42+
43+
let _ = std::io::stdin().read_line(&mut String::new());
3144

32-
std::process::exit(rc);
45+
let backtrace = backtrace::Backtrace::new();
46+
47+
println!("\n{:?}\n", backtrace);
48+
println!("Hit Enter to continue.");
49+
50+
let _ = std::io::stdin().read_line(&mut String::new());
51+
}));
52+
}
53+
54+
fn main() {
55+
setup_panic();
56+
console::attach();
57+
let ret = std::panic::catch_unwind(gui::spawn_gui);
58+
console::free();
59+
60+
if ret.is_err() {
61+
std::process::exit(1);
62+
}
3363
}

0 commit comments

Comments
 (0)