ozboomer has asked for the wisdom of the Perl Monks concerning the following question:

The following simple program works Ok but it has a couple of anomalies that I don't understand. Granted, I'm still fiddling about with Perl/Tk and am still coming to grips with how and when things happen with events... but there are still a few questions.

The main Perl program:

use Win32::Process; use Win32; use Tk; $cmd = "utest.bat"; # Spawned command $mw = MainWindow->new( ); my $mylbl = $mw->Label(-text => 'Click Start')->pack( ); my $olbl = $mw->Label(-text => "(no output)")->pack( ); $mw->Button(-text => "Exit", -command => sub { exit })->pack( ); my $mybtn = $mw->Button( -text => 'Start', -command => \&myjob )->pack( ); MainLoop; sub myjob { $mylbl->configure(-text => 'Running...'); &myjob2; # Option 1 # my @res = `$cmd`; # Option 2 # $olbl->configure(-text => $res[0]); # Option 2 $mylbl->configure(-text => 'Completed!', -foreground => 'red'); } sub myjob2 { Win32::Process::Create($ProcessObj, "C:\\windows\\system32\\notepad.exe", "notepad c:\\tmp\\temp.txt", 0, NORMAL_PRIORITY_CLASS, ".")|| die ErrorReport(); $ProcessObj->Wait(INFINITE); } sub ErrorReport{ print Win32::FormatMessage( Win32::GetLastError() ); }

The program UTEST.BAT:

@echo off sleep -t 5 echo SLEEP IS DONE

With "Option 1" enabled in the code:

a) When the 'Start' button is pressed and the spawned process is created, the 'Start' button remains pressed. Is there a way the button can be 'restored' to its unpressed state or is there another way that the call should be made?

b) After Notepad starts (and grabs focus, with it's window at the 'front'), within 7 seconds (on my PC) the title bar of the calling program goes dim like it's lost focus. Why is there a delay? Can more than one window have focus at the same time!?

c) Why is the "Running" text never displayed, although the "Completed" text is?

"Option 2" is more like 'reality' for my application. I want to spawn off a call to a non-GUI program and use the output in my Perl/Tk application.

I'm using ActiveState perl v5.8.7 under WinXP-SP2.

Any thoughts or suggestions?

Replies are listed 'Best First'.
Re: More Perl/Tk Queries with Spawned Processes under Win32
by GrandFather (Saint) on May 08, 2006 at 00:56 UTC
    $ProcessObj->Wait(INFINITE);

    a/ Says 'wait for ever or until the process terminates'. That stalls the creating script until the created task completes. Omit the Wait and the creating script will continue to run. You can monitor the state of the created process using the process object.

    b/ I don't know

    c/ Because the script isn't running until notepad closes the running text doesn't get updated until notepad closes, then gets overwritten anyway.

    The following should help sort out the process stuff:

    sub myjob2 { Win32::Process::Create(my $ProcessObj, "C:\\windows\\system32\\notepad.exe", "notepad noname.txt", 0, NORMAL_PRIORITY_CLASS, ".")|| die ErrorReport(); my $exitcode; $mw->update () while $ProcessObj->GetExitCode($exitcode), $exitcod +e == 259; print $exitcode; }

    DWIM is Perl's answer to Gödel

      This suggestion works very well, with some modifications... many thanks for your help!

      I'm not sure if I should put this next item in another question by itself... but as it's related to the current program...

      It's always a bugbear that when using Win32::Process::Create, complete paths need to be specified in the call, rather than letting the PATH search mechanisms find the program I want to run.

      In the current example, this means we have to specify the call like:

      Win32::Process::Create($ProcessObj, "C:\\windows\\system32\\notepad.exe", "notepad c:\\tmp\\del.me", 0, NORMAL_PRIORITY_CLASS, ".")|| die ErrorReport();

      I'd like to know how people get around this problem, particularly when programs are placed in non-standard locations (although the programs may be found on PATH).

      I've had a look in 'SuperSearch' but had no joy. One thought would be to collect the list of directories in PATH via File::Spec->path() and then use File::Find on the result. Alternatively, there seems to be a module on CPAN called File::PathList which (I think) returns the fully-pathed filespec directly.

      Any other thoughts? ...and many thanks for any forthcoming suggestions :)

        You could allow the shell to do the path resolution for you:

        Win32::Process::Create( $obj, "C:\\windows\\system32\\cmd.exe", 'cmd /c notepad somefile', 0, NORMAL_PRIORITY_CLASS, '.' ) or die $^E;;

        Or more simply use system

        ## Run the command asyncronously with shell command resolution $pid = system 1, 'notepad'; .... ## Do other stuff ## Retrieve the exit code waitpid $pid, 0; print 'command return status: ', $? >> 8;; command return status: 0

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: More Perl/Tk Queries with Spawned Processes under Win32
by ozboomer (Friar) on May 09, 2006 at 09:28 UTC

    Well, here we go... another version that uses the 'system' call (thanks, BrowserUk)...

    use Win32::Process; use Win32; use Tk; $cmd = "utest.bat"; # Spawned command $mw = MainWindow->new( ); my $mylbl = $mw->Label(-text => 'Click Start')->pack( ); my $byebtn = $mw->Button(-text => "Exit", -command => sub { exit })->p +ack( ); my $mybtn = $mw->Button( -text => 'Start', -command => \&myjob )->pack( ); &reset_disp; MainLoop; sub myjob # ------------------------------ { &create_file_sys; &show_file_sys; &reset_disp; } sub create_file # ------------------------------ { $mylbl->configure(-text => 'Running...'); $mw->update; Win32::Process::Create(my $ProcessObj, "c:\\windows\\system32\\cmd.exe", "cmd /c utest.bat del.me", 0, NORMAL_PRIORITY_CLASS, ".")|| die ErrorReport(); $mw->update () while $ProcessObj->GetExitCode($exitcode), $exitcode + == 259; } sub create_file_sys # ------------------------------ { $mylbl->configure(-text => 'Running...'); $byebtn->configure(-state => disabled); $mw->update; my $pid = system 1, 'utest.bat', 'del.me'; waitpid $pid, 0; } sub show_file # ------------------------------ { $mylbl->configure(-text => 'Completed!', -foreground => 'red'); $mw->update; Win32::Process::Create($ProcessObj2, "C:\\windows\\system32\\notepad.exe", "notepad del.me", 0, NORMAL_PRIORITY_CLASS, ".")|| die ErrorReport(); $ProcessObj2->Wait(INFINITE); } sub show_file_sys # ------------------------------ { $mylbl->configure(-text => 'Completed!', -foreground => 'red'); $byebtn->configure(-state => disabled); $mw->update; my $pid = system 1, 'notepad', 'del.me'; waitpid $pid, 0; } sub reset_disp # ------------------------------ { $mylbl->configure(-text => 'Click Start', -foreground => 'black'); $byebtn->configure(-state => active); $mw->update; }

    ...and the (trivially) revised UTEST.BAT:

    @echo off :sleep -t 2 echo SLEEP IS DONE at %TIME% > %1

    I'm still struggling a mite with the 'events' but I think I have something that works the way I want it to. An old thought of mine returns: if you can't get things to work, over-modularize it... and that's what I've done. At least it helps my understanding... and it does what I want.

    As usual, the Monks have been very helpful... Thanks one 'n all :)