Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Win32::OLE freezing Tk

by Takamoto (Monk)
on Dec 23, 2019 at 14:37 UTC ( [id://11110552]=perlquestion: print w/replies, xml ) Need Help??

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

Hello monks

I have the following basic Tk application that uses Win32::OLE to copy a PPT files to another locaction (the task is not important here, it is just to illustrate my problem). The application works fine, but it freezes for a long time, even after the OLE operation has been concluded and the message window "Done!" is shown and closed.

Can this behaviour be solved? If not, how can I show my message "Done!" only after the GUI is reactive? The problem is that the user thinks s/he has control over the GUI as soon as the "Done!" message is shown.

Furthermore: shouldn't $ppt->{Visible} = 0; prevent the PowerPoint application to show up?

use strict; use warnings; use utf8; use Tk; use Try::Tiny; use Win32::OLE; use Win32::OLE::Const qw( Microsoft.PowerPoint ); use Win32::OLE::Enum; my $mw = Tk::MainWindow->new( -width => 160, -height => 120, ); $mw->packPropagate(0); # Button erstellen: my $but = $mw->Button( -text => "Save PPT", -command => \&save_PPT, ); $but->pack(); my $quit_btn = $mw->Button( -text => "Exit", -command => \&quit_program, ); $but->pack(); $quit_btn->pack(); $mw->MainLoop(); sub save_PPT { my $filename = "C:\\Users\\Taka\\Desktop\\original.pptx"; my $ppt; try { $ppt = Win32::OLE->GetActiveObject('PowerPoint.Application') + } catch { die $_ } ; unless ( $ppt ) { $ppt = Win32::OLE->new( 'PowerPoint.Application', sub { $_[0]->Quit } ) or return 'error'; } $ppt->{Visible} = 0; my $presentation = $ppt->Presentations->Open($filename, 1); my $slides = Win32::OLE::Enum->new( $presentation->Slides ); $presentation->SaveAs("SAVED_" . $filename); $presentation->Close; $mw->messageBox (-title => "message", -message=>"DONE!", -icon=> 'info +'); } sub quit_program { exit(0); }

Any suggestion would be very much appreciated.

Replies are listed 'Best First'.
Re: Win32::OLE freezing Tk
by Corion (Patriarch) on Dec 23, 2019 at 15:37 UTC

    Most likely, the delay is when shutting down Powerpoint as $ppt goes out of scope.

    You can test this theory by explicitly clearing out $ppt yourself:

    $presentation->SaveAs("SAVED_" . $filename); $presentation->Close; undef $ppt; # Clean up Powerpoint $mw->messageBox (-title => "message", -message=>"DONE!", -icon=> 'info +');

    There is very little way around this, but if you plan to convert more than a single presentation in one go, it might make sense to declare $ppt as a global variable and keep it around:

    our $ppt; sub save_PPT { # ... $ppt ||= Win32::OLE->GetActiveObject('PowerPoint.Application'); # ... and also later: $ppt ||= Win32::OLE->new( 'PowerPoint.Application', sub { $_[0]->Quit } ) or return 'error'; # ---

      Thank you, Corion. undef $ppt; seems to do the trick. I am not sure how this can let PowerPoint shut down without keeping the GUI occupied, but it works.

        If you are concerned about performance can't you just copy the file without opening the file in PowerPoint and using the 'save as' option?

        Perhaps this (edit: undef $ppt;) just kills PP as opposed to shutdown/close?

Re: Win32::OLE freezing Tk
by jcb (Parson) on Dec 24, 2019 at 00:00 UTC

    The problem is that you are performing a long-running task on the GUI thread and not returning control to the Tk MainLoop often enough. This is a fundamental mismatch, since Tk is event-based and long-running callbacks will hang the GUI. I usually encounter this with network interaction when combining Tk and LWP in the same program; my usual solution is to fork and handle LWP operations in child processes, passing results back over a pair of pipes (one monitored by Tk in non-blocking mode and one in blocking mode for passing large binary results up using Storable) but this probably will not work well on Windows.

    I suggest looking into the threads support in perl; you may need a few shared variables for passing state between the threads. I have no idea how to get the Tk event loop to handle thread completion.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11110552]
Approved by marto
Front-paged by stevieb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (5)
As of 2024-04-18 20:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found