use strict; use warnings; sub read_file_contents { my $fname = shift; open( my $fh, '<', $fname ) or die "error: open '$fname': $!\n"; local $/ = undef; # slurp mode my $s = <$fh>; close($fh); return $s; } # Run a Windows executable synchronously. # Return a three element list: # the return code; the stdout of the command; and the stderr of the command. # Die if something goes wrong. sub run_cmd_sync { my ( $exe, $cmd, $workdir ) = @_; defined($workdir) or $workdir = "."; require Win32::Process; my $tmpout = "klink-out-$$.tmp"; my $tmperr = "klink-err-$$.tmp"; -f $exe or die "error: file '$exe' not found"; local *SAVOUT; local *SAVERR; # save original stdout and stderr open( SAVOUT, ">&STDOUT" ) or die "error: open SAVOUT: $!"; open( SAVERR, ">&STDERR" ) or die "error: open SAVERR: $!"; open( STDOUT, '>', $tmpout ) or die "error: can't redirect stdout"; open( STDERR, '>', $tmperr ) or die "error: can't redirect stderr"; Win32::Process::Create( my $hProc, # process object $exe, # executable $cmd, # command line 1, # inherit handles Win32::Process::NORMAL_PRIORITY_CLASS(), $workdir # working dir ) or die "error: Win32::Process::Create: $^E ($!)"; my $pid = $hProc->GetProcessID(); # parent continues (redirect back to original) ... close(STDOUT); close(STDERR); open( STDOUT, ">&SAVOUT" ) or die "error: open SAVOUT: $!"; open( STDERR, ">&SAVERR" ) or die "error: open SAVERR: $!"; print "started exe:$exe (cmd:$cmd) ok, pid=$pid.\n"; my $rc = 0; $hProc->Wait( Win32::Process::INFINITE() ) or die "error: Wait: $^E ($!)"; $hProc->GetExitCode($rc) or die "error: GetExitCode: $^E ($!)"; my $outstr = read_file_contents($tmpout); my $errstr = read_file_contents($tmperr); unlink($tmpout) or die "error: unlink '$tmpout': $!\n"; unlink($tmperr) or die "error: unlink '$tmperr': $!\n"; return ( $rc, $outstr, $errstr ); } my ( $rc, $outstr, $errstr ) = run_cmd_sync( $^X, 'perl -e "print q{hello stdout}; print STDERR q{hello stderr}"', '.' ); print "rc='$rc'\n"; print "stdout='$outstr'\n"; print "stderr='$errstr'\n"; #### started exe:C:\Strawberry\perl\bin\perl.exe (cmd:perl -e "print q{hello stdout}; print STDERR q{hello stderr}") ok, pid=3132. rc='0' stdout='hello stdout' stderr='hello stderr' #### # Test program tt1.pl use strict; use warnings; # Run a command without invoking the command shell. # exe is the command name # @_ contains the command line arguments (including argv[0]) sub run_cmd_noshell { my $exe = shift; print "run '$exe' with args:\n '@_'\n"; system { $exe } @_; my $rc = $? >> 8; $rc == 0 or warn "error: exit code=$rc\n"; } run_cmd_noshell($^X, $^X, '-le', 'print q{hello one};'); run_cmd_noshell($^X, 'perl', '-le', 'print q{hello two}; exit 42;'); #### run 'C:\Strawberry\perl\bin\perl.exe' with args: 'C:\Strawberry\perl\bin\perl.exe -le print q{hello one};' hello one run 'C:\Strawberry\perl\bin\perl.exe' with args: 'perl -le print q{hello two}; exit 42;' hello two error: exit code=42