@@ -175,8 +175,7 @@ impl Command {
175
175
si. dwFlags = c:: STARTF_USESTDHANDLES ;
176
176
177
177
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 ) ?;
180
179
181
180
// stolen from the libuv code.
182
181
let mut flags = c:: CREATE_UNICODE_ENVIRONMENT ;
@@ -220,7 +219,7 @@ impl Command {
220
219
si. hStdError = stderr. raw ( ) ;
221
220
222
221
unsafe {
223
- cvt ( c:: CreateProcessW ( ptr:: null ( ) ,
222
+ cvt ( c:: CreateProcessW ( app_name . unwrap_or ( ptr:: null ( ) ) ,
224
223
cmd_str. as_mut_ptr ( ) ,
225
224
ptr:: null_mut ( ) ,
226
225
ptr:: null_mut ( ) ,
@@ -424,7 +423,31 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
424
423
425
424
// Produces a wide string *without terminating null*; returns an error if
426
425
// `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
+
428
451
// Encode the command and arguments in a command line string such
429
452
// that the spawned process may recover them using CommandLineToArgvW.
430
453
let mut cmd: Vec < u16 > = Vec :: new ( ) ;
@@ -433,7 +456,9 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
433
456
cmd. push ( ' ' as u16 ) ;
434
457
append_arg ( & mut cmd, arg) ?;
435
458
}
436
- return Ok ( cmd) ;
459
+
460
+ cmd. push ( 0 ) ; // add null terminator
461
+ return Ok ( ( app, cmd) ) ;
437
462
438
463
fn append_arg ( cmd : & mut Vec < u16 > , arg : & OsStr ) -> io:: Result < ( ) > {
439
464
// 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>>)
498
523
}
499
524
500
525
fn make_dirp ( d : Option < & OsString > ) -> io:: Result < ( * const u16 , Vec < u16 > ) > {
501
-
502
526
match d {
503
527
Some ( dir) => {
504
528
let mut dir_str: Vec < u16 > = ensure_no_nuls ( dir) ?. encode_wide ( ) . collect ( ) ;
@@ -515,12 +539,13 @@ mod tests {
515
539
use super :: make_command_line;
516
540
517
541
#[ test]
518
- fn test_make_command_line ( ) {
542
+ fn test_make_command_line_with_out_env ( ) {
519
543
fn test_wrapper ( prog : & str , args : & [ & str ] ) -> String {
520
544
let command_line = & make_command_line ( OsStr :: new ( prog) ,
521
545
& args. iter ( )
522
546
. map ( |a| OsString :: from ( a) )
523
- . collect :: < Vec < OsString > > ( ) )
547
+ . collect :: < Vec < OsString > > ( ) ,
548
+ None )
524
549
. unwrap ( ) ;
525
550
String :: from_utf16 ( command_line) . unwrap ( )
526
551
}
0 commit comments