#!/usr/bin/perl -w use strict; my($myAbout) = "______________________________________________________________________________ Written for Amins by an Admin. Keep in mind our systems are currently win2k and winxp Parts of this app were from pieces of examples and research. For now this app works fine, once I learn more perl maybe I'll add to it. Constructive Ideas welcome. Author: Gary A. Frost (Gary.Frost\@arnold.af.mil) This program uses PSTools (pskill,psshutdown), pstools path must be in the environment path procinfo.ico and this app should be placed in the PSTools folder. The following modules are needed to run this program as is. File::Compare Win32 Win32::GUI Win32::PerfLib Win32::API Env Tk TK::Text Sort::ArrayOfArrays Config::IniFiles Win32::MachinePropInfo (this is my custom module) ______________________________________________________________________________"; use File::Compare; use Win32::GUI; use Win32; use Win32::PerfLib; use Win32::API; use Env qw(@PATH); #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- shows the task list like the task manager but of any computer #______________________________________________________________________________ my ($host) = @ARGV; my ($sortv) = 'a0'; my ($sortitem) = 0; my ($refresh_rate) = 3000; my ($count_down) = 20; my ($icon,$tray,$pw,$PopupMenu,$tX,$tY); my ($IniFile) = 'procinfo.ini'; my ($firstresize) = 1; my ($resizing) = 0; my ($activating) = 0; my ($gui_minwidth) = 845; my ($gui_minheight) = 525; my ($minimized) = 0; #default colors my %RGBColor = ( Background => [0x80,0x80,0x80], Foreground => [0xff,0xff,0xff] ); my ($TkBgColor) = "#808080"; my ($TkFgColor) = "#ffffff"; my ($sourcepath) = "\\\\aedcgw03\\f\$\\projects\\library\\misc\\procinfo"; my ($rebootmessage) = "System being rebooted by Aministrator"; my ($started) = 1; my ($win,$autorefresh,$CurDir,$kill_ret); my ($oldCursor,$sh,$sw); #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- set the wait cursor to show when busy. #______________________________________________________________________________ my $loadImage = new Win32::API ('user32', 'LoadImage', ['N','N','I','I','I','I'],'N') or die 'cannot find LoadImage function'; my $waitCursor = $loadImage->Call(0, 32514, 2, 0, 0, 0x8040); foreach (@PATH) { if($_ =~ /PSTOOLS/i) { $CurDir = $_ . "\\"; } } ReadIniFile(); #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- create the gui screen #______________________________________________________________________________ my $ms_win = Win32::GUI::GetDesktopWindow(); my $msw = Win32::GUI::Width($ms_win); my $msh = Win32::GUI::Height($ms_win); my ($x, $y, $tw, $th) = MidWin($msw, $msh); my ($font) = new Win32::GUI::Font(-name => "Arial Bold", -size => 18); my ($r_font) = new Win32::GUI::Font(-name=>"Arial", -size => 16); my ($b_font) = new Win32::GUI::Font(-name=>"Arial Bold", -size => 16); $PopupMenu = new Win32::GUI::Menu( "Menu" => "ProcInfo", " >Set Source Path" => "SetSourcePath", " >-" => 0, " >Set Reboot Message" => "SetRebootMessage", " >-" => 0, " >PC Information" => "Host_Info", " >-" => 0, " >Hide Program" => "HideProcInfo", " >Show Program" => "ShowProcInfo", " >-" => 0, " >Background Color" => "SetBgColor", " >Foreground Color" => "SetFgColor", " >-" => 0, " >Check For Update" => "CheckStatus", " >-" => 0, " >About" => "About", " >-" => 0, " >Exit" => "ExitProcInfo", ); $icon = new Win32::GUI::Icon('procinfo.ico'); $win = Win32::GUI::Window->new( # -topmost=>1, -left => $x-($x/2), -top => $y-($y/2), # -width => $gui_width, -height => 525 , -minwidth => $gui_minwidth, -minheight => $gui_minheight, # -controlbox => 0, #put the menu (defined in "$PopupMenu" above) onto the window -menu => $PopupMenu, -name => "win", -style => WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME, -text=> "Process Information" ); $win->{-dialogui} = 1; #This will enable the tab stuff $win->ChangeSmallIcon($icon); $tray = $win->AddNotifyIcon( -icon => $icon, -id => 1, -name => "tray", -tip => "ProcInfo", ); $win->AddTextfield(-name => "HostName", -tabstop => 1, -left => 50, -top => 5, -width => 100, -height => 20, -group => 1, -text => $host, -font => $b_font ); $win->AddButton(-text => "Connect to Host", -name => "btn_Connect", -addstyle => BS_DEFPUSHBUTTON, -tabstop => 1, -left => 160, -top => 5, -width => 110, -height => 20, -default => 'active', -state => 'active', -ok => 1, -font =>$b_font ); $win->AddButton(-text => "Refresh", -name => "btn_refresh", -addstyle => BS_DEFPUSHBUTTON, -tabstop => 1, -left => $gui_minwidth - 85, -top => 35, -width => 70, -height => 20, -font =>$r_font ); $win->AddCheckbox(-text => "", -name => "chk_Auto", -tabstop => 1, -left => $gui_minwidth - 110, -top => 65, -width => 13, -height => 13, -font =>$r_font, ); $win->AddTextfield(-name => "txt_RefreshRate", -tabstop => 1, -left => $gui_minwidth - 100, -top => 130, -width => 70, -height => 30, -text => $refresh_rate / 1000, -font => $r_font ); $win->AddUpDown(-name => "ud_RefreshRate", -left => $gui_minwidth - 80, -width => 20, -height => 30, -top => 130 ); $win->ud_RefreshRate->Range(3,180); $win->ud_RefreshRate->Pos($refresh_rate / 1000); # create the ListView $win->AddListView( -name => "ListView", -text => "", -left => 9, -top => 30, -width => $gui_minwidth - 125, -height => 440, -style => WS_CHILD | WS_VISIBLE | 1, -fullrowselect => 1, -gridlines => 1, -showselalways => 1, -font => $r_font, #-singlesel => 1, #-checkboxes => 1, #-hottrack => 1, ); my ($lw) = $win->ListView->ScaleWidth; # create the columns in the list view $win->ListView->InsertColumn( -index => 0, -width => $lw/6, -text => "Image Name", ); $win->ListView->InsertColumn( -index => 1, -subitem => 1, -width => $lw/14, -text => "PID", ); $win->ListView->InsertColumn( -index => 2, -subitem => 1, -width => $lw/18, -text => "CPU", ); $win->ListView->InsertColumn( -index => 3, -subitem => 1, -width => $lw/8, -text => "CPU-Time", ); $win->ListView->InsertColumn( -index => 4, -subitem => 1, -width => $lw/8, -text => "Mem Usage", ); $win->ListView->InsertColumn( -index => 5, -subitem => 1, -width => $lw/9, -text => "PF Delta", ); $win->ListView->InsertColumn( -index => 6, -subitem => 1, -width => $lw/9, -text => "VM Size", ); $win->ListView->InsertColumn( -index => 7, -subitem => 1, -width => $lw/9, -text => "Base Pri", ); $win->ListView->InsertColumn( -index => 8, -subitem => 1, -width => $lw/10, -text => "Threads", ); # Hidden Column (used for deleting row(s)) $win->ListView->InsertColumn( -index => 9, -subitem => 1, -width => 0, -text => "Loaded", ); $win->AddButton(-text => "Kill Process", -name => "btn_Kill", -addstyle => BS_DEFPUSHBUTTON, -tabstop => 1, -left => $gui_minwidth - 90, -top => 210, -width => 80, -height => 20, -font =>$b_font ); $win->btn_Kill->Disable(); $win->AddButton(-text => "Reboot", -name => "btn_reboot", -addstyle => BS_DEFPUSHBUTTON, -tabstop => 1, -left => $gui_minwidth - 85, -top => 250, -width => 70, -height => 20, -font =>$r_font ); $win->AddTextfield(-name => "txt_countdown", -tabstop => 1, -left => $gui_minwidth - 100, -top => 295, -width => 70, -height => 30, -text => $count_down, -font => $r_font ); $win->AddUpDown(-name => "ud_countdown", -left => $gui_minwidth - 80, -width => 20, -height => 30, -top => 295 ); $win->ud_countdown->Range(0,3600); $win->ud_countdown->Pos($count_down); $win->AddButton(-text => "Exit", -name => "btn_Exit", -addstyle => BS_DEFPUSHBUTTON, -tabstop => 1, -left => $gui_minwidth - 80, -top => 450, -width => 70, -height => 20, -font =>$b_font ); $win->AddStatusBar(-name => "Status"); $win->HostName->SetFocus(); $win->AddTimer("RefeshPids", $refresh_rate); $win->RefeshPids->Kill; $win->ListView->Hide(); if($host) { GetConnection(); } $win->Show(); $sh = $win->ScaleHeight; Win32::GUI::Dialog(); $win->Hide(); #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Events #______________________________________________________________________________ #-- GUI Window Events #______________________________________________________________________________ sub win_Activate { $sh = $win->ScaleHeight; if($sh == 0 and !$firstresize) { $minimized = 1; } if(!$firstresize) { if(!$activating) { if(!$minimized) { $activating = 1; RepaintMainWindow(); } elsif($minimized) { if($sh) { $minimized = 0; ResizeControls(); } } elsif(!$resizing) { $activating = 1; ResizeControls(); } } elsif($activating) { if($minimized) { if($sh) { $minimized = 0; ResizeControls(); } } elsif(!$minimized) { RepaintMainWindow(); } } elsif(!$resizing) { $activating = 1; ResizeControls(); } } if(!$sh) { $activating = 0; } } sub win_Deactivate { $sh = $win->ScaleHeight; if($sh == 0) { $minimized = 1; } else { $resizing = 0; } } sub win_Minimize { $minimized = 1; $resizing = 1; $activating = 1; } sub win_Maximize { # print "Maximize\n"; } sub win_Resize { if(!$activating and !$minimized and ($sh or $firstresize)) { $resizing = 1; ResizeControls(); $resizing = 0; } $firstresize = 0; } sub win_Terminate { $win->Disable(); $win->Hide(); $tray->DESTROY(); return -1; } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Button Events #______________________________________________________________________________ sub btn_Exit_Click { win_Terminate(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- kill one or more process #______________________________________________________________________________ sub btn_Kill_Click { my (@selected) = $win->ListView->SelectedItems(); my ($sel,$exitcode,%kpid,$hash); foreach $sel (@selected) { push (@{$kpid{$sel}}, $win->ListView->ItemInfo($sel,1)); } $hash = \%kpid; foreach $sel (keys %kpid) { $win->Status->Text("Killing process $hash->{$sel}->[1]"); $kill_ret = system($CurDir."pskill.exe $host $hash->{$sel}->[1]"); if(!$kill_ret) { $win->Status->Text("Process $hash->{$sel}->[1] is Dead"); } elsif($kill_ret =~ 65280) { $win->Status->Text("Unable to kill process $hash->{$sel}->[1]: Access is denied"); } else { $win->Status->Text("Unable to kill process $hash->{$sel}->[1]: Error Code: $kill_ret"); } } RefreshPids(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- reboot remote host #______________________________________________________________________________ sub btn_reboot_Click { if($host) { $win->Status->Text("Rebooting $host"); $kill_ret = system($CurDir."psshutdown.exe -f -r -m \"$rebootmessage\" -t $count_down $host"); if(!$kill_ret) { $win->Status->Text("Reboot Sent"); } else { $win->Status->Text("Unable to Reboot $host: Error Code: $kill_ret"); } } } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- connect to the host and get the process info #______________________________________________________________________________ sub btn_Connect_Click { $win->ListView->Clear(); GetConnection(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- manually refresh #______________________________________________________________________________ sub btn_refresh_Click { if($autorefresh) { $win->RefeshPids->Kill; } RefreshPids(); if($autorefresh) { $win->RefeshPids->Interval($refresh_rate); } } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- text field events #______________________________________________________________________________ sub txt_RefreshRate_Change { if(!$started) { my ($tmptext) =$win->txt_RefreshRate->Text; if($tmptext < 3 and $tmptext ne '') { $refresh_rate = 3000; } else { $refresh_rate = $tmptext * 1000; } $win->ud_RefreshRate->Pos($refresh_rate / 1000); if($win->chk_Auto->GetCheck()) { $win->RefeshPids->Interval($refresh_rate); } if($tmptext ne '') { WriteIniFile(); } } } sub txt_countdown_Change { if(!$started) { my ($tmptext) =$win->txt_countdown->Text; if($tmptext < 0 and $tmptext ne '') { $count_down = 20; } else { $count_down = $tmptext; } $win->ud_countdown->Pos($count_down); if($tmptext ne '') { WriteIniFile(); } } } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Up Down events #______________________________________________________________________________ sub ud_RefreshRate_Scroll { my ($tmptext) =$win->txt_RefreshRate->Text; if($tmptext eq '') { $refresh_rate = 3000; } elsif($tmptext < 3) { $refresh_rate = 3000; } else { $refresh_rate = $tmptext * 1000; } if($win->chk_Auto->GetCheck()) { $win->RefeshPids->Interval($refresh_rate); } WriteIniFile(); } sub ud_countdown_Scroll { my ($tmptext) =$win->txt_countdown->Text; if($tmptext eq '') { $count_down = 20; } elsif($tmptext < 3) { $count_down = 20; } else { $count_down = $tmptext * 1000; } WriteIniFile(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- check box events #______________________________________________________________________________ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- turn on/off auto refresh #______________________________________________________________________________ sub chk_Auto_Click { SetRefreshRate(); } sub lbl_Rate_Click { if($win->chk_Auto->GetCheck()) { $win->chk_Auto->SetCheck(0); } else { $win->chk_Auto->SetCheck(1); } SetRefreshRate(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Monitory System Tray Icon Menu events #______________________________________________________________________________ sub tray_RightClick { $resizing = 1; ($tX, $tY) = Win32::GUI::GetCursorPos(); $win->TrackPopupMenu($PopupMenu->{ProcInfo},$tX, $tY); $resizing = 0; } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Popup Menu and Tray Menu Events #______________________________________________________________________________ sub CheckStatus_Click { if(-e $CurDir . "procinfo.exe") { my ($compare_ret) = compare($CurDir . "procinfo.exe",$sourcepath . "\\procinfo.exe"); if ($compare_ret == 1) { $win->Status->Text("A newer file is located at $sourcepath"); } elsif($compare_ret == 0) { $win->Status->Text('Program is up to date'); } elsif($compare_ret == -1) { $win->Status->Text("Source not found at $sourcepath"); } } else { $win->Status->Text("procinfo.exe not found at " . $CurDir . "procinfo.exe"); } } sub SetSourcePath_Click { $win->Hide(); $win->Disable(); use Tk; use TK::Text; my ($swin) = new MainWindow; $swin->configure(-title=>'Source Path',-background=>$TkBgColor,-foreground=>$TkFgColor); #don't allow resize or x to close window $swin->resizable(0,0); $swin->protocol('WM_DELETE_WINDOW',sub{return;}); my ($lb) = $swin->Label(-text => 'Source Path',-background=>$TkBgColor,-foreground=>$TkFgColor); $lb->pack; my ($editdialog) = $swin->Text(-height=>1,-width=>120,-takefocus=>1); $editdialog->insert('1.0',$sourcepath); $editdialog->bind('Tk::Text','' => sub {$editdialog->focusNext;}); $editdialog->bind('Tk::Text','' => sub {$editdialog->focusNext;}); $editdialog->pack; my ($exit_button) = $swin->Button(-text=>'Save and Close',-width=>15,-command=>sub{ $sourcepath = $editdialog->get('1.0','1.0 lineend'); WriteIniFile(); $win->Enable(); $win->Show(); $swin->destroy; })->pack(-pady=>5,-expand=>1); my ($cancel_button) = $swin->Button(-text=>'Cancel',-width=>10,-command=>sub{ $win->Enable(); $win->Show(); $swin->destroy; })->pack(-pady=>5,-expand=>1); MainLoop; } sub SetRebootMessage_Click { $win->Hide(); $win->Disable(); use Tk; use TK::Text; my ($swin) = new MainWindow; $swin->configure(-title=>'Reboot Message',-background=>$TkBgColor,-foreground=>$TkFgColor); #don't allow resize or x to close window $swin->resizable(0,0); $swin->protocol('WM_DELETE_WINDOW',sub{return;}); my ($lb) = $swin->Label(-text => 'Reboot Message',-background=>$TkBgColor,-foreground=>$TkFgColor); $lb->pack; my ($editdialog) = $swin->Text(-height=>4,-width=>120,-takefocus=>1,-wrap=>'word'); $editdialog->insert('1.0',$rebootmessage); $editdialog->bind('Tk::Text','' => sub {$editdialog->focusNext;}); $editdialog->pack; my ($exit_button) = $swin->Button(-text=>'Save and Close',-width=>15,-command=>sub{ $rebootmessage = $editdialog->get('1.0','end'); WriteIniFile(); $win->Enable(); $win->Show(); $swin->destroy; })->pack(-pady=>5,-expand=>1); my ($cancel_button) = $swin->Button(-text=>'Cancel',-width=>10,-command=>sub{ $win->Enable(); $win->Show(); $swin->destroy; })->pack(-pady=>5,-expand=>1); MainLoop; } sub Host_Info_Click { if($host) { use Win32::MachinePropInfo; my (%info); if (Win32::MachinePropInfo::GetMachinePropInfo($host, \%info)) { use Text::ParseWords; my($this_os); my (@env_paths) = &parse_line(';+',1,$info{'environment_path'}); $this_os = "System:\n" . $info{'product_name'} . "\n"; $this_os .= $info{'osversion'} . "." . $info{'osbuild'} . "\n"; $this_os .= "\n\nComputer:\n " . $info{'memory'} . " RAM"; $this_os .= "\n " . $info{'processor_identifier'}; $this_os .= "\n " . $info{'processor_name'}; $this_os .= "\n " . $info{'processor_speed'}; $this_os .= "\n " . $info{'system_bios_version'}; $this_os .= "\n BIOS Date: " . $info{'system_bios_date'}; $this_os .= "\n\n System Environment Paths:\n"; my ($doit) = 1; my($premsg,$postmsg); my ($search) = "\\;"; my ($tpath); while($doit) { my (@tevn); my (@n_evn); foreach $tpath (@env_paths) { if($tpath !~ /%/g) { $tpath =~ /$search/; $premsg = $`; $postmsg = $'; if($&) { if($premsg) { push @tevn, $premsg; } if($postmsg) { push @tevn, $postmsg; } } else { push @n_evn, $tpath } } else { push @n_evn, $tpath } } if(@tevn) { $doit = 1; foreach (@tevn) { push @n_evn, $_; } my ($T); for($T=$#env_paths;$T>=0;$T--) { pop @env_paths; } foreach (@n_evn) { push @env_paths, $_; } } else { $doit = 0; } } foreach (@env_paths) { $this_os .= "\n $_"; } Win32::MsgBox($this_os , MB_ICONINFORMATION , "$host Information"); } } } sub About_Click { Win32::MsgBox($myAbout , MB_ICONINFORMATION , "About"); } sub ExitProcInfo_Click { win_Terminate(); } sub ShowProcInfo_Click { $win->Show(); RepaintMainWindow(); } sub HideProcInfo_Click { $win->Hide(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Window background colors #______________________________________________________________________________ sub SetBgColor_Click { use Tk; my $w = new MainWindow; $w->withdraw; my ($colorp) = $w->chooseColor(); if($colorp) { $TkBgColor = $colorp; $colorp =~ /#/; $colorp = $'; my ($c1,$c2,$c3); $c1 = "0x" . substr $colorp, 0, 2; $c2 = "0x" . substr $colorp, 2, 2; $c3 = "0x" . substr $colorp, 4, 2; $RGBColor{Background} = [hex $c1,hex $c2,hex $c3]; } $w->destroy; WriteIniFile(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Window foreground colors #______________________________________________________________________________ sub SetFgColor_Click { use Tk; my $w = new MainWindow; $w->withdraw; my ($colorp) = $w->chooseColor(); if($colorp) { $TkFgColor = $colorp; $colorp =~ /#/; $colorp = $'; my ($c1,$c2,$c3); $c1 = "0x" . substr $colorp, 0, 2; $c2 = "0x" . substr $colorp, 2, 2; $c3 = "0x" . substr $colorp, 4, 2; $RGBColor{Foreground} = [hex $c1,hex $c2,hex $c3]; } $w->destroy; WriteIniFile(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- ListView Events #______________________________________________________________________________ #-- Clicking on header sorts by that column #______________________________________________________________________________ sub ListView_ColumnClick { my ($item) = @_; if($item eq $sortitem) { $sortitem = "-$item"; } else { $sortitem = $item; } SortView(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Selects a row to kill #______________________________________________________________________________ sub ListView_ItemClick { $win->btn_Kill->Enable(); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- Timer Events #______________________________________________________________________________ sub RefeshPids_Timer { if($win->ListView->Count() gt 0) { if($autorefresh) { $win->RefeshPids->Kill; } RefreshPids(); if($autorefresh) { $win->RefeshPids->Interval($refresh_rate); } } } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- custom subroutines #______________________________________________________________________________ sub MidWin { my ($w, $h) = @_; my $x = $w/4; my $y = $h/4; $w = $w/2; $h = $h/2; return ($x, $y, $w, $h); } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- listview subroutines #______________________________________________________________________________ sub InsertListItem { my($name, $pid, $cpu, $hour, $minute, $seconds, $memusage, $pf, $vm, $priority, $threads,$loaded) = @_; my $item = $win->ListView->InsertItem(-item => $win->ListView->Count(), -text => $name); $win->ListView->SetItem(-item => $item,-subitem => 1,-text => $pid); $win->ListView->SetItem(-item => $item,-subitem => 2,-text => sprintf("%2d",$cpu)); $win->ListView->SetItem(-item => $item,-subitem => 3, -text => sprintf("%3d:%02d:%02d",$hour, $minute, $seconds)); $win->ListView->SetItem(-item => $item,-subitem => 4,-text => &commify ($memusage) . " K"); $win->ListView->SetItem(-item => $item,-subitem => 5,-text => $pf); $win->ListView->SetItem(-item => $item,-subitem => 6,-text => &commify ($vm) . " K"); $win->ListView->SetItem(-item => $item,-subitem => 7,-text => $priority); $win->ListView->SetItem(-item => $item,-subitem => 8,-text => $threads); $win->ListView->SetItem(-item => $item,-subitem => 9,-text => $loaded); } sub SortView { use Sort::ArrayOfArrays; my $X; my @sarry; my @tmp; my $sort; my $results; my ($count) = $win->ListView->Count(); for($X=0;$X < $count; $X++) { my @tarry; @tmp = $win->ListView->ItemInfo($X); $tarry[0] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,1); $tarry[1] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,2); $tarry[2] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,3); $tarry[3] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,4); $tarry[4] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,5); $tarry[5] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,6); $tarry[6] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,7); $tarry[7] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,8); $tarry[8] = $tmp[1]; @tmp = $win->ListView->ItemInfo($X,9); $tarry[9] = $tmp[1]; push @sarry, [$tarry[0],$tarry[1],$tarry[2],$tarry[3],$tarry[4], $tarry[5],$tarry[6],$tarry[7],$tarry[8],$tarry[9]]; } $sort = Sort::ArrayOfArrays->new({ results => \@sarry, sort_column => $sortitem, }); $results = $sort->sort_it; for($X=0;$X < $count; $X++) { $win->ListView->SetItem(-index => $X, -subitem => 0, -text => $results->[$X][0]); $win->ListView->SetItem(-index => $X, -subitem => 1, -text => $results->[$X][1]); $win->ListView->SetItem(-index => $X, -subitem => 2, -text => $results->[$X][2]); $win->ListView->SetItem(-index => $X, -subitem => 3, -text => $results->[$X][3]); $win->ListView->SetItem(-index => $X, -subitem => 4, -text => $results->[$X][4]); $win->ListView->SetItem(-index => $X, -subitem => 5, -text => $results->[$X][5]); $win->ListView->SetItem(-index => $X, -subitem => 6, -text => $results->[$X][6]); $win->ListView->SetItem(-index => $X, -subitem => 7, -text => $results->[$X][7]); $win->ListView->SetItem(-index => $X, -subitem => 8, -text => $results->[$X][8]); $win->ListView->SetItem(-index => $X, -subitem => 9, -text => $results->[$X][9]); } } sub ConnectHost { my ($perflib); $perflib = new Win32::PerfLib($host); if($perflib) { $win->Status->Text("Connected to $host"); } else { $win->Status->Text("$host NOT Found"); return; } RefreshPids($perflib); } sub RefreshPids { my ($perflib) = @_; my ($process_obj,$p,$process_id,$processor_time,$elapsed,$memory,$page_faults); my ($virtual_memory,$priority,$threads); my ($proc_ref0,$proc_ref1,$instance_ref0,$instance_ref1); my ($counter_ref0,$counter_ref1,$i,%process,%id); my ($Numerator0,$Denominator0,$Numerator1,$Denominator1); my (%proc_time,%cputime,%memory,%page_faults,%virtual_memory,%priority,%threads); my ($id,$seconds,$hour,$minute,$prio); my ($X,$itemFound,@current,$refresh,$pitemFound); my ($now_time); Win32::GUI::SetCursor($waitCursor); #show hourglass ... $now_time = gmtime; $process_obj = 230; $process_id = 784; $processor_time = 6; $elapsed = 684; $memory = 180; $page_faults = 28; $virtual_memory = 186; $priority = 682; $threads = 680; if(!$perflib) { $perflib = new Win32::PerfLib($host); } $proc_ref0 = {}; $proc_ref1 = {}; $perflib->GetObjectList($process_obj, $proc_ref0); $perflib->GetObjectList($process_obj, $proc_ref1); $perflib->Close(); $instance_ref0 = $proc_ref0->{Objects}->{$process_obj}->{Instances}; $instance_ref1 = $proc_ref1->{Objects}->{$process_obj}->{Instances}; foreach $p (keys %{$instance_ref0}) { $counter_ref0 = $instance_ref0->{$p}->{Counters}; $counter_ref1 = $instance_ref1->{$p}->{Counters}; foreach $i (keys %{$counter_ref0}) { next if $instance_ref0->{$p}->{Name} eq "_Total"; if($counter_ref0->{$i}->{CounterNameTitleIndex} == $process_id) { $process{$counter_ref0->{$i}->{Counter}} = $instance_ref0->{$p}->{Name}; $id{$counter_ref0->{$i}->{Counter}} = $p; } elsif($counter_ref0->{$i}->{CounterNameTitleIndex} == $processor_time) { $Numerator0 = $counter_ref0->{$i}->{Counter}; $Denominator0 = $proc_ref0->{PerfTime100nSec}; $Numerator1 = $counter_ref1->{$i}->{Counter}; $Denominator1 = $proc_ref1->{PerfTime100nSec}; if(($Denominator1 - $Denominator0 ) * 100 > 0) { $proc_time{$p} = ($Numerator1 - $Numerator0) / ($Denominator1 - $Denominator0 ) * 100; } $cputime{$p} = int($counter_ref1->{$i}->{Counter} / 10000000); } elsif($counter_ref0->{$i}->{CounterNameTitleIndex} == $memory) { $memory{$p} = int($counter_ref0->{$i}->{Counter} / 1024); } elsif($counter_ref0->{$i}->{CounterNameTitleIndex} == $page_faults) { $page_faults{$p} = $counter_ref1->{$i}->{Counter}; } elsif($counter_ref0->{$i}->{CounterNameTitleIndex} == $virtual_memory) { $virtual_memory{$p} = int($counter_ref0->{$i}->{Counter} / 1024); } elsif($counter_ref0->{$i}->{CounterNameTitleIndex} == $priority) { $priority{$p} = $counter_ref0->{$i}->{Counter}; } elsif($counter_ref0->{$i}->{CounterNameTitleIndex} == $threads) { $threads{$p} = $counter_ref0->{$i}->{Counter}; } } } #Update process info, insert new ones foreach $p (keys %process) { $itemFound = 0; $id = $id{$p}; $seconds = $cputime{$id}; $hour = int($seconds / 3600); $seconds -= $hour * 3600; $minute = int($seconds / 60); $seconds -= $minute * 60; if ($priority{$id} > 15) { $prio = "Realtime"; } elsif ($priority{$id} > 10 ) { $prio = "High"; } elsif ($priority{$id} > 5 ) { $prio = "Normal"; } elsif ($priority{$id} > 0 ) { $prio = "Low"; } else { $prio = "Unknown"; } for($X=0;$X < $win->ListView->Count();$X++) { @current = $win->ListView->ItemInfo($X); my ($imagename) = $current[1]; @current = $win->ListView->ItemInfo($X,1); my ($procid) = $current[1]; if($imagename eq ucfirst $process{$p} and $procid eq $p) { $itemFound = 1; $win->ListView->SetItem(-item => $X,-subitem => 2, -text => sprintf("%2d",$proc_time{$id})); $win->ListView->SetItem(-item => $X,-subitem => 3, -text => sprintf("%3d:%02d:%02d",$hour, $minute, $seconds)); $win->ListView->SetItem(-item => $X,-subitem => 4, -text => &commify ($memory{$id}) . " K"); $win->ListView->SetItem(-item => $X,-subitem => 5, -text => $page_faults{$id}); $win->ListView->SetItem(-item => $X,-subitem => 6, -text => &commify ($virtual_memory{$id}) . " K"); $win->ListView->SetItem(-item => $X,-subitem => 7, -text => $prio); $win->ListView->SetItem(-item => $X,-subitem => 8, -text => $threads{$id}); $win->ListView->SetItem(-item => $X,-subitem => 9, -text => 'Yes'); } } if(!$itemFound) { $refresh = 1; InsertListItem(ucfirst $process{$p}, $p,$proc_time{$id}, $hour, $minute, $seconds, $memory{$id}, $page_faults{$id}, $virtual_memory{$id}, $prio, $threads{$id},'Yes'); } } # remove process that no longer exists for($X=0;$X < $win->ListView->Count();$X++) { $pitemFound = 0; @current = $win->ListView->ItemInfo($X); foreach $p (keys %process) { if($current[1] eq ucfirst $process{$p}) { $pitemFound = 1; } } if(!$pitemFound) { $win->ListView->DeleteItem($X); } } SortView(); my ($mdc) = $win->GetDC; $mdc->BackColor($RGBColor{Background}); $mdc->TextColor($RGBColor{Foreground}); $mdc->SelectObject($win); $mdc->TextOut(290, 6, "Process Count: ". $win->ListView->Count()); Win32::GUI::SetCursor($oldCursor); #show previous arrow cursor aga } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #-- format the number fields #______________________________________________________________________________ sub commify { local $_ = shift; #$_ .= '.00' if not /\./; # make sure . and at least #$_ .= '00'; # 2 trailing 0's 1 while s/^(-?\d+)(\d{3})/$1,$2/; # do commas s/^([^\.]*?)\.(\d{2}).*$/sprintf "%s.%02u", $1, $2/e; # format it return $_; } sub GetConnection { $oldCursor = Win32::GUI::SetCursor($waitCursor); #show hourglass ... if($host) { $host =~ s/\\//g; } if ($win->HostName->Text gt '') { $host = '\\\\' . $win->HostName->Text; } elsif($host) { $host = '\\\\' . $host; } else { $host = '\\\\' . Win32::NodeName(); } $win->Status->Text("Connecting to $host"); ConnectHost(); $host =~ s/\\//g; $win->HostName->Text($host); $host = '\\\\' . $host; if($autorefresh) { $win->RefeshPids->Interval($refresh_rate); } Win32::GUI::SetCursor($oldCursor); #show previous arrow cursor aga } sub ReadIniFile { use Config::IniFiles; my ($cfg); $cfg = Config::IniFiles->new(); if(-e $CurDir . $IniFile) { $cfg->SetFileName($CurDir . $IniFile ); $cfg->ReadConfig(); # set the screen colors $TkBgColor = $cfg->val('Background','Color'); my ($Red,$Green,$Blue); $Red = "0x" . substr $TkBgColor, 0, 2; $Green = "0x" . substr $TkBgColor, 2, 2; $Blue = "0x" . substr $TkBgColor, 4, 2; $RGBColor{Background} = [hex $Red,hex $Green,hex $Blue]; $TkBgColor = "#" . $TkBgColor; $TkFgColor = $cfg->val('Foreground','Color'); $Red = "0x" . substr $TkFgColor, 0, 2; $Green = "0x" . substr $TkFgColor, 2, 2; $Blue = "0x" . substr $TkFgColor, 4, 2; $RGBColor{Foreground} = [hex $Red,hex $Green ,hex $Blue]; $TkFgColor = "#" . $TkFgColor; if($cfg->SectionExists('Refresh')) { $refresh_rate = $cfg->val('Refresh','Rate',$refresh_rate); $sourcepath = $cfg->val('Source','Path',$sourcepath); } if($cfg->SectionExists('Reboot')) { $count_down = $cfg->val('Reboot','Countdown',$count_down); $rebootmessage = $cfg->val('Reboot','Message',$rebootmessage); } } else { $cfg->WriteConfig($CurDir . $IniFile); $cfg->AddSection('Background'); $cfg->newval('Background','Color','808080'); $cfg->AddSection('Foreground'); $cfg->newval('Foreground','Color','ffffff'); $cfg->AddSection('Refresh'); $cfg->newval('Refresh','Rate',$refresh_rate); $cfg->AddSection('Source'); $cfg->newval('Source','Path',$sourcepath); $cfg->AddSection('Reboot'); $cfg->newval('Reboot','Countdown',$count_down); $cfg->newval('Reboot','Message',$rebootmessage); $cfg->WriteConfig($CurDir . $IniFile); ## set the screen colors #$TkBgColor = "#808080"; #$TkFgColor = "#ffffff"; #$RGBColor{Background} = [0x80,0x80,0x80]; #$RGBColor{Foreground} = [0xff,0xff,0xff]; } } sub WriteIniFile { use Config::IniFiles; my ($cfg); $cfg = Config::IniFiles->new( -file => $CurDir . $IniFile); $TkBgColor =~ /#/; $cfg->setval("Background","Color",$'); $TkFgColor =~ /#/; $cfg->setval("Foreground","Color",$'); if($cfg->SectionExists('Refresh')) { $cfg->setval("Refresh","Rate",$refresh_rate); $cfg->setval("Source","Path",$sourcepath); } else { $cfg->AddSection('Refresh'); $cfg->newval('Refresh','Rate',$refresh_rate); $cfg->AddSection('Source'); $cfg->newval('Source','Path',$sourcepath); } if($cfg->SectionExists('Reboot')) { $cfg->setval('Reboot','Countdown',$count_down); $cfg->setval('Reboot','Message',$rebootmessage); } else { $cfg->AddSection('Reboot'); $cfg->newval('Reboot','Countdown',$count_down); $cfg->newval('Reboot','Message',$rebootmessage); } $cfg->WriteConfig($CurDir . $IniFile); } sub ResizeControls { if(!$started) { $win->ListView->Hide(); } my ($sw) = $win->ScaleWidth; my ($sh) = $win->ScaleHeight; if($sw < ($gui_minwidth - 8) and $sh >= 498) { $win->Resize($gui_minwidth,$sh + 27); } elsif($sw >= ($gui_minwidth - 8) and $sh < 498) { $win->Resize($sw + 8,525); } elsif($sw <= ($gui_minwidth - 8) and $sh <= 498) { $win->Resize($gui_minwidth,525); } $sw = $win->ScaleWidth; $sh = $win->ScaleHeight; $win->Status->Move(0, $sh - $win->Status->Height); $win->Status->Resize($sw, $win->Status->Height); $win->ListView->Move(9, 30); $win->ListView->Resize($sw - 117, $sh - 58); $win->btn_Exit->Move($sw - 72, $sh - 48); $win->btn_refresh->Move($sw - 77, 35); $win->chk_Auto->Move($sw - 100, 65); $win->txt_RefreshRate->Move($sw - 92, 130); $win->txt_countdown->Move($sw - 92, 295); $win->ud_RefreshRate->Move($sw - 42, 130); $win->ud_countdown->Move($sw - 42, 295); $win->btn_Kill->Move($sw - 82, 210); $win->btn_reboot->Move($sw - 82, 250); my ($width) = $win->ListView->ScaleWidth; $win->ListView->ColumnWidth(0,$width/6); $win->ListView->ColumnWidth(1,$width/14); $win->ListView->ColumnWidth(2,$width/18); $win->ListView->ColumnWidth(3,$width/8); $win->ListView->ColumnWidth(4,$width/8); $win->ListView->ColumnWidth(5,$width/9); $win->ListView->ColumnWidth(6,$width/9); $win->ListView->ColumnWidth(7,$width/9); $win->ListView->ColumnWidth(8,$width/10); if(!$started) { $win->ListView->Show(); } $started = 0; if(!$firstresize) { RepaintMainWindow(); } } sub SetRefreshRate { if($win->chk_Auto->GetCheck()) { $autorefresh = 1; $win->btn_refresh->Disable(); $win->RefeshPids->Interval($refresh_rate); } else { $autorefresh = 0; $win->btn_refresh->Enable(); $win->RefeshPids->Kill; } } sub RepaintMainWindow { HideControls(); ShowControls(); my ($width) = $win->Width; my ($height) = $win->Height; my ($h,$w,$linetext); $linetext = ""; for($w=0;$w < $width;$w++) { $linetext .= " "; } my ($mdc) = $win->GetDC; $mdc->BackColor($RGBColor{Background}); $mdc->TextColor($RGBColor{Foreground}); $mdc->SelectObject($win); for($h=0;$h < $height;$h++) { $mdc->TextOut(0, $h, $linetext); } $mdc->TextOut(15, 6, "Host"); $mdc->TextOut(290, 6, "Process Count: ". $win->ListView->Count()); my ($sw) = $win->ScaleWidth; $mdc->TextOut($sw - 85, 63, "Auto Refresh"); $mdc->TextOut($sw - 92, 105, "Refresh Rate"); $mdc->TextOut($sw - 92, 275, "Reboot Timer"); } sub HideControls { $win->HostName->Hide(); $win->btn_Connect->Hide(); $win->ListView->Hide(); $win->btn_Exit->Hide(); $win->btn_refresh->Hide(); $win->chk_Auto->Hide(); $win->txt_RefreshRate->Hide(); $win->txt_countdown->Hide(); $win->btn_Kill->Hide(); $win->btn_reboot->Hide(); $win->ud_RefreshRate->Hide(); $win->ud_countdown->Hide(); $win->Status->Hide(); } sub ShowControls { $win->HostName->Show(); $win->btn_Connect->Show(); $win->ListView->Show(); $win->btn_Exit->Show(); $win->btn_refresh->Show(); $win->chk_Auto->Show(); $win->txt_RefreshRate->Show(); $win->txt_countdown->Show(); $win->btn_Kill->Show(); $win->btn_reboot->Show(); $win->ud_RefreshRate->Show(); $win->ud_countdown->Show(); $win->Status->Show(); }