views:

1095

answers:

2

I have a Perl script that launches another Perl script in a new console through Win32::Process as follows:

Win32::Process::Create($ProcessObj,
                      "C:\\Perl\\bin\\perl.exe",
                      "$path_to_other_perl_script",
                      0,
                      NEW_CONSOLE,
                      ".");

$ProcessObj->Suspend();
$ProcessObj->Resume();
$ProcessObj->Wait(0);

The problem is, there is no stdout in the new console created. If I don't use the new console option, the script runs silently in the background.

If I use cmd.exe to launch the Perl script, I can see the output fine but now I cannot control the child Perl script through Win32::Process.

Does anyone have a solution that works?

A: 

Using -w before $filepath fixed it ! Still need an explanation though.

Naseer
+4  A: 

Update: Based on your comments, I get the feeling that your programs are not examples of best practices on Linux or Windows. However, I am sure, when reading the documentation for Win32::Process, you noticed that you can call the Kill method on the process to terminate it. So, I changed the example below to do that.

Your chances of getting useful help increase exponentially if you provide real code. Here are the arguments to Win32::Process::Create:

$iflags: flag: inherit calling processes handles or not

Now, I am not sure if you are trying to capture the STDOUT of the second process or if you are trying to have its STDOUT output show up in the same console as the parent.

If the latter, then the following scripts illustrate one way of doing that:

parent.pl

#!/usr/bin/perl

use strict;
use warnings;

use Win32;
use Win32::Process;

$| = 1;

my $p;

print "Starting child process ... \n";

Win32::Process::Create(
    $p,
    'c:/opt/perl/bin/perl.exe',
    'perl hello.pl',
    1,
    NORMAL_PRIORITY_CLASS,
    '.',
) or die Win32::FormatMessage( Win32::GetLastError() );

print "Waiting three seconds before killing 'hello.pl'\n";

for (1 .. 3) {
    print;
    sleep 1;
}
$p->Kill(0)
    or die "Cannot kill '$p'";

hello.pl

#!/usr/bin/perl

$| = 1;

print "Hello World\n";
print "Sleeping 1000 seconds\n";

for (1 .. 1000) {
    sleep 1;
    print '.';
}

Output:

Starting child process ...
Waiting three seconds before killing 'hello.pl'
1Hello World
Sleeping 1000 seconds
2.3.

Now, I am still not sure why you are using Win32::Process. Unless there is a specific reason to tie your script to Win32, I would recommend using standard Perl facilities. For example, read perldoc -f open and perldoc perlipc (see esp. Using open for IPC).

Explain your question better to get answers that address your particular situation rather than generalities.

Sinan Ünür
If I create the process through the system command, I was not able to find any method to terminate the process on win32. On Linux I just used system("kill -9 -$$") to kill the perl script and all it's children but couldn't find anything so simple on Windows
Naseer
http://speculation.org/garrick/kill-9.html All kidding aside, I find `system("kill -9 -$$")` suspect. `fork` works on Windows: `fork` your children, save their `pid`s and `wait` on them or `kill` them as you see fit. I prefer http://search.cpan.org/perldoc/Parallel::ForkManager
Sinan Ünür
Tried that and would love to do that - however, if I fork() and then call my child script through exec or system, the PID of the exec'd process is different from the PID returned by fork.
Naseer
Watch out with forking on Windows. It's fine for a couple of processes, but I've had lots of problems with Windows handling hundreds of them from the same process.
brian d foy
@brian d foy I never gone above a few dozen (and that in only one program). Thank you for pointing that out.
Sinan Ünür
@Naseer if you have questions about IPC in Perl, you should formulate a separate question and post it. Your specific question has been answered: Set the `iflags` argument to `Win32::Process::Create`.
Sinan Ünür
@Sinan, Thanks for your detailed replies, I was using the Kill command in Win32 Process anyway. I had tried setting the $iflags, but specifying "perl hello.pl" (or using -w as mentioned in my answer) seems to be doing the trick. I did try open but it didn't work either and hence this method.I am not a perl programmer - this script is just a quick hack to get something done at work and it needed perl - hence the bad practices.
Naseer
@Naseer Thank you for accepting my answer. However, I had forgotten about the pseudo-processes `fork` launches on Windows. So, you are right, `fork` + `exec` + `kill` would not work. I am glad `Win32::Process` worked for you. So, I guess the answer to your question was that the `$cmdline` parameter has to include the name of the executable you are running + the command line arguments. I don't think you can rely on `-w` making it work.
Sinan Ünür