Skip to content

Commit 6b9b6f1

Browse files
author
Salim Afiune
committed
On batch files set ApplicationName to cmd.exe
If the program is a BATCH file CreateProcess requires to start the command interpreter by setting ApplicationName to `cmd.exe` and CommandLine to the following arguments: `/c` plus the name of the batch file. Signed-off-by: Salim Afiune <[email protected]>
1 parent 41a0df0 commit 6b9b6f1

File tree

2 files changed

+34
-8
lines changed

2 files changed

+34
-8
lines changed

src/libstd/sys/windows/env.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ pub mod os {
1616
pub const DLL_EXTENSION: &'static str = "dll";
1717
pub const EXE_SUFFIX: &'static str = ".exe";
1818
pub const EXE_EXTENSION: &'static str = "exe";
19+
pub const BATCH_EXTENSIONS: &'static str = vec!["bat", "cmd"];
1920
}

src/libstd/sys/windows/process.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,7 @@ impl Command {
175175
si.dwFlags = c::STARTF_USESTDHANDLES;
176176

177177
let program = program.as_ref().unwrap_or(&self.program);
178-
let mut cmd_str = make_command_line(program, &self.args)?;
179-
cmd_str.push(0); // add null terminator
178+
let (app_name, cmd_str) = make_command_line(program, &self.args, &self.env)?;
180179

181180
// stolen from the libuv code.
182181
let mut flags = c::CREATE_UNICODE_ENVIRONMENT;
@@ -220,7 +219,7 @@ impl Command {
220219
si.hStdError = stderr.raw();
221220

222221
unsafe {
223-
cvt(c::CreateProcessW(ptr::null(),
222+
cvt(c::CreateProcessW(app_name.unwrap_or(ptr::null()),
224223
cmd_str.as_mut_ptr(),
225224
ptr::null_mut(),
226225
ptr::null_mut(),
@@ -424,7 +423,31 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
424423

425424
// Produces a wide string *without terminating null*; returns an error if
426425
// `prog` or any of the `args` contain a nul.
427-
fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
426+
fn make_command_line(prog: &OsStr, args: &[OsString],
427+
env: Option<&collections::HashMap<OsString, OsString>>)
428+
-> io::Result<(Option<Vec<u16>>, Vec<u16>)> {
429+
// If the program is a BATCH file we must start the command interpreter; set
430+
// ApplicationName to cmd.exe and set CommandLine to the following arguments:
431+
// `/c` plus the name of the batch file.
432+
let mut app: Option<Vec<u16>> = None;
433+
let ext = Path::new(prog).extension();
434+
let batch = env::consts::BATCH_EXTENSIONS.iter().find(|&&x| x == ext);
435+
if batch.is_some() {
436+
if let Some(e) = env {
437+
if let Some(cmd_exe) = e.get("COMSPEC") {
438+
app = Some(ensure_no_nuls(cmd_exe)?.encode_wide().collect());
439+
}
440+
}
441+
// If we were unable to find COMSPEC, default to `cmd.exe`
442+
if !app.is_some() {
443+
app = Some(OsStr::new("cmd.exe").encode_wide().collect());
444+
}
445+
// Prepend the argument to the program
446+
let mut cmd_prog = OsString::from("cmd /c ");
447+
cmd_prog.push(prog);
448+
let prog = cmd_prog.as_os_str();
449+
}
450+
428451
// Encode the command and arguments in a command line string such
429452
// that the spawned process may recover them using CommandLineToArgvW.
430453
let mut cmd: Vec<u16> = Vec::new();
@@ -433,7 +456,9 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
433456
cmd.push(' ' as u16);
434457
append_arg(&mut cmd, arg)?;
435458
}
436-
return Ok(cmd);
459+
460+
cmd.push(0); // add null terminator
461+
return Ok((app, cmd));
437462

438463
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr) -> io::Result<()> {
439464
// If an argument has 0 characters then we need to quote it to ensure
@@ -498,7 +523,6 @@ fn make_envp(env: Option<&collections::HashMap<OsString, OsString>>)
498523
}
499524

500525
fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
501-
502526
match d {
503527
Some(dir) => {
504528
let mut dir_str: Vec<u16> = ensure_no_nuls(dir)?.encode_wide().collect();
@@ -515,12 +539,13 @@ mod tests {
515539
use super::make_command_line;
516540

517541
#[test]
518-
fn test_make_command_line() {
542+
fn test_make_command_line_with_out_env() {
519543
fn test_wrapper(prog: &str, args: &[&str]) -> String {
520544
let command_line = &make_command_line(OsStr::new(prog),
521545
&args.iter()
522546
.map(|a| OsString::from(a))
523-
.collect::<Vec<OsString>>())
547+
.collect::<Vec<OsString>>(),
548+
None)
524549
.unwrap();
525550
String::from_utf16(command_line).unwrap()
526551
}

0 commit comments

Comments
 (0)