Skip to content

Commit

Permalink
Add option for attaching GUI applications to a console
Browse files Browse the repository at this point in the history
  • Loading branch information
Systemcluster committed Nov 18, 2023
1 parent bbeb06e commit 4e8e380
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 20 deletions.
13 changes: 7 additions & 6 deletions README.md
Expand Up @@ -63,7 +63,7 @@ Options:
-i, --show-information <SHOW_INFORMATION>
Information output details (title, verbose, none) [default: title]
-n, --console <CONSOLE>
Show or attach to a console window (auto, always, never) [default: auto]
Show or attach to a console window (auto, always, never, attach) [default: auto]
-w, --current-dir
Set the current working directory of the target to the unpack directory
-l, --list-runners
Expand Down Expand Up @@ -138,15 +138,16 @@ It defaults to `title`. Error information is always shown when applicable.

This option controls if the runner should attach to a console or if a console window should be opened when launching a Windows application from the Windows explorer. Accepted values are:

* `auto`: Select the console behavior based on the subsystem of the input executable if available. If not available, it will be disabled for Windows runners, and enabled for all other runners.
* `always` Always attach to or open a console.
* `never`: Never open or attach to a console.
* `auto`: Select the console behavior based on the subsystem of the input executable if available. If not available, it will fall back to `never` for Windows runners, and `always` for all other runners.
* `always` Always attach to or open a console. The runner will block the console until the packed executable exits.
* `never`: Never open or attach to a console. The runner will immediately exit after launching the packed executable.
* `attach`: Never open a new console window, but attach to an existing console if available. The runner will unblock the console immediately, but output will still be shown.

It defaults to `auto`. This option currently only affects Windows runners, other runners will always attach to a console if available.
It defaults to `auto`. This option currently only affects Windows runners, other runners will always attach to a console if available. This option will also not prevent packed Windows command line applications from opening a console on their own when launched from the Windows explorer.

#### current-dir

By default the working directory of the unpacked executable is set to the working directory of the runner executable. This flag changes the working directory to the unpack directory.
By default the working directory of the packed executable is set to the working directory of the runner executable. This flag changes the working directory to the unpack directory.

## Compilation

Expand Down
15 changes: 11 additions & 4 deletions src/args.rs
Expand Up @@ -174,11 +174,18 @@ pub fn get_show_information(show_information: &str) -> u8 {
}
}

pub fn get_show_console(show_console: &str, runner_name: &str) -> bool {
pub fn get_show_console(show_console: &str, runner_name: &str) -> u8 {
match show_console.to_lowercase().as_str() {
"auto" => !runner_name.contains("windows"),
"always" => true,
"never" => false,
"auto" => {
if runner_name.contains("windows") {
0
} else {
1
}
}
"never" => 0,
"always" => 1,
"attach" => 2,
_ => {
println!(
"{}: {}",
Expand Down
8 changes: 4 additions & 4 deletions src/main.rs
Expand Up @@ -50,7 +50,7 @@ pub struct Args {
/// Information output details (title, verbose, none)
#[arg(short = 'i', long, default_value = "title")]
show_information: String,
/// Show or attach to a console window (auto, always, never)
/// Show or attach to a console window (auto, always, never, attach)
#[arg(short = 'n', long, default_value = "auto")]
console: String,
/// Set the current working directory of the target to the unpack directory
Expand Down Expand Up @@ -161,7 +161,7 @@ fn main() {

let decompressed = (|| -> Result<Vec<u8>, Box<dyn Error>> {
let mut runner_image = Image::parse(&decompressed)?;
runner_image.set_subsystem(if show_console { 3 } else { 2 });
runner_image.set_subsystem(if show_console == 1 { 3 } else { 2 });
Ok(runner_image.data().to_owned())
})()
.unwrap_or_else(|error| {
Expand All @@ -187,7 +187,7 @@ fn main() {
.cloned()
.unwrap_or_default();
if args.console == "auto" {
show_console = command_image.subsystem() == 3;
show_console = if command_image.subsystem() == 3 { 1 } else { 0 };
runner_image.set_subsystem(command_image.subsystem());
}
runner_image.set_resource_directory(command_resources)?;
Expand Down Expand Up @@ -274,7 +274,7 @@ fn main() {

let info = StarterInfo {
signature: [0x50, 0x45, 0x33, 0x44, 0x41, 0x54, 0x41, 0x00],
show_console: show_console.into(),
show_console,
current_dir: args.current_dir.into(),
verification,
show_information,
Expand Down
4 changes: 4 additions & 0 deletions startpe/Cargo.toml
Expand Up @@ -25,3 +25,7 @@ rayon = "1.7.0"
twox-hash = { version = "1.6.3", default-features = false }
zerocopy = "0.6.1"
zstd = { version = "0.12.3", default-features = false, features = ["arrays"] }

[target.'cfg(windows)'.dependencies]

winapi = { version = "0.3.9", features = ["wincon"] }
43 changes: 37 additions & 6 deletions startpe/src/main.rs
@@ -1,15 +1,21 @@
use std::{
env::current_exe,
fs::{read_link, File},
io::Write,
mem::size_of,
panic::set_hook,
process::Command,
};

#[cfg(any(unix, target_os = "redox"))]
use std::os::unix::process::CommandExt;
#[cfg(not(any(unix, target_os = "redox")))]
use std::process::Stdio;
#[cfg(windows)]
use std::{io::Write, time::SystemTime};
use std::time::SystemTime;

#[cfg(windows)]
use winapi::um::wincon::{AttachConsole, ATTACH_PARENT_PROCESS};

use memmap2::MmapOptions;
use zerocopy::LayoutVerified;
Expand Down Expand Up @@ -66,6 +72,17 @@ fn main() {
.into_ref();

let show_information = info.show_information;
let show_console = info.show_console;

#[cfg(not(windows))]
let console_attached = false;
#[cfg(windows)]
let mut console_attached = false;
#[cfg(windows)]
if show_console == 2 || (show_console == 0 && show_information == 2) {
console_attached = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) != 0 };
}

if show_information >= 1 {
println!(
"{} {}{}",
Expand Down Expand Up @@ -110,6 +127,10 @@ fn main() {
if show_information >= 2 {
println!();
println!("version: {}", version);
println!(
"show console: {} (attached: {})",
show_console, console_attached
);
}

let unpack_root = match info.unpack_target {
Expand Down Expand Up @@ -209,6 +230,10 @@ fn main() {
println!("running...");
}

if console_attached && show_console == 0 {
let _ = std::io::stdout().flush();
}

let mut command = Command::new(run_path);
command.args(baked_arguments);
command.args(forwarded_arguments);
Expand All @@ -222,13 +247,19 @@ fn main() {
}
#[cfg(not(any(unix, target_os = "redox")))]
{
if show_console == 0 || (show_console == 2 && !console_attached) {
command.stdout(Stdio::null());
command.stderr(Stdio::null());
command.stdin(Stdio::null());
}
let mut child = command
.spawn()
.unwrap_or_else(|e| panic!("failed to run {}: {}", run_path.display(), e));
let result = child
.wait()
.unwrap_or_else(|e| panic!("failed to run {}: {}", run_path.display(), e));

std::process::exit(result.code().unwrap_or(0))
if show_console == 1 || (show_console == 2 && console_attached) {
let result = child
.wait()
.unwrap_or_else(|e| panic!("failed to run {}: {}", run_path.display(), e));
std::process::exit(result.code().unwrap_or(0))
}
}
}

0 comments on commit 4e8e380

Please sign in to comment.