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

I've got this perl/tk app that sits in the system tray (windows). When you lick on it small window opens and presents two options to the user via radio buttons. What I'm trying to do is get the small window to open when the user is logging out/restarting or rebooting. This way they can select one of the radio buttons. Here is the sample code I'm working with trying to catch a system event via wmi. What I'm having an issue with right now is identifying the class info to define the query. I think __Systemevents is the right area, but can't find helpful documentation.
use Win32::OLE qw(EVENTS); use Win32::Console; my $console = Win32::Console->new(STD_INPUT_HANDLE); my $refWMI = Win32::OLE->GetObject('winMgmts:'); my $refSink = Win32::OLE->new ('WBemScripting.SWbemSink'); Win32::OLE->WithEvents($refSink,\&eventCallback); my $strQuery = "SELECT * FROM __SessionEndingEventHandler " . "WITHIN 10 WHERE TargetInstance ISA '\Win32_Service\'"; $refWMI->ExecNotificationQueryAsync($refSink, $StrQuery); print "Waiting for Events ...\n"; my $continueLooping = 1; while ($continueLooping) { if ($console->GetEvents()!= 0){ my @cons = $console->Input(); if ($cons[1] != 0){ undef $countingLooping; } } Win32::OLE->SpinMessageLoop(); Win32::Sleep(500); } $refSink->Cancel(); Win32::OLE->WithEvents($refSink); undef $refSink; undef $refWMI; undef $console; print "Finished.\n"; sub eventCallback() { my ($refSource,$refEventName,$refEvent,$refEvent,$refContext) += @_; if ($refEventName eq "onObjectReady") { print $refEvent->TargetInstance->{Name} . " has " . ($refEvent->TargetInstance->{Started} ? "started" : "stopped") . "\n"; } }

Replies are listed 'Best First'.
Re: Catching system events, via WMI
by igelkott (Priest) on Feb 09, 2008 at 22:38 UTC
    Commands to be run when logging off can be set in the Group Policy (gpedit.msc) if using XP pro, etc.
      Well it seems this can't be don't that easily. Windows WMI doesn't provide a userlogout event via wmi, seems via .net though. So change of plans. Can a service running with the system account control the win32:gui window running as the current logged in user? Like grab the win32::gui handle? examples? Got this bit of perl win32::gui code working and would like to either have the code once running in the systray poll a stat file and if the stat file exists then open its diallog for user input. OR have the system service control the diallog popup. New to the win32:gui and not sure where to put the code to run while the gui is sitting there waiting for the user.
      #!perl -w use strict; use warnings; use Win32::GUI; my $DOS = Win32::GUI::GetPerlWindow(); Win32::GUI::Hide($DOS); # Get text to diaply from the command line my $text = defined($ARGV[0]) ? $ARGV[0] : "Software Update Notificatio +n"; # Create a font to diaply the text my $font = Win32::GUI::Font->new( -name => "Comic Sans MS", -size => 24, ); my $main = Win32::GUI::Window->new( -name => 'Main', -text => 'CTG Updates', -width => 300, -height => 200 ); # Add the text to a label in the window my $label = $main->AddLabel( -text => $text, -font => $font, -foreground => 0x0000FF, ); my $icon = new Win32::GUI::Icon('GUIPERL.ICO'); my $ni = $main->AddNotifyIcon( -name => "NI", -id => 1, -icon => $icon, -tip => "CTG Updater" ); $main->AddRadioButton( -name => 'Default', -text => 'Apply updates now', -default => 1, # Give button darker border -ok => 1, # press 'Return' to click this button -width => 125, -height => 20, -left => $main->ScaleWidth() - 200, -top => $main->ScaleHeight() - 100, ); $main->AddRadioButton( -name => 'Cancel', -text => 'Update Another time', -cancel => 1, # press 'Esc' to click this button -width => 125, -height => 20, -left => $main->ScaleWidth() - 200, -top => $main->ScaleHeight() - 80, ); my $textfield = $main->AddTextfield( -name => "Textfield", -text => "have fun and more", -left => 75, -top => 150, -width => 200, -height => 40, -readonly => 1, ); #Win32::GUI::Dialog(); #sleep 30; $main->Show(); Win32::GUI::Dialog(); exit(0); sub Main_Terminate { return -1; } sub Main_Minimize { $main->Disable(); $main->Hide(); return 1; } sub NI_Click { $main->Enable(); $main->Show(); return 1; } sub Default_Click { print "Default button clicked\n"; $main->Hide(); return 0; } sub Cancel_Click { print "Cancel button clicked\n"; $main->Hide(); return 0; }
        While it's possible that I'm seriously misunderstanding the issue, I do believe that it's completely unnecessary to catch the logout event because Windows already has this hook built-in. See this technet explanation. The links on that page offer more details.

        In other words, your script will only be triggered on this event so there will never be a need to look for it -- it'll only run when appropriate.