=head1 NAME Win32::Process::Info::PT - Provide process information via Proc::ProcessTable. =head1 SYNOPSIS This package fetches process information on a given machine, using Dan Urist's B. This makes the 'Win32::' part of our name bogus, but lets one use the same basic interface under a wider range of operating systems. use Win32::Process::Info $pi = Win32::Process::Info->new (undef, 'PT'); $pi->Set (elapsed_as_seconds => 0); # In clunks, not seconds. @pids = $pi->ListPids (); # Get all known PIDs @info = $pi->GetProcInfo (); # Get the max CAVEAT USER: This package does not support access to a remote machine, because the underlying API doesn't. If you specify a machine name (other than '', 0, or undef) when you instantiate a new Win32::Process::Info::PT object, you will get an exception. This package is B intended to be used independently; instead, it is a subclass of Win32::Process::Info, and should only be called via that package. =head1 DESCRIPTION The main purpose of the Win32::Process::Info package is to get whatever information is convenient (for the author!) about one or more processes. GetProcInfo (which see) is therefore the most-important method in the package. See it for more information. Unless explicitly stated otherwise, modules, variables, and so on are considered private. That is, the author reserves the right to make arbitrary changes in the way they work, without telling anyone. For subroutines, variables, and so on which are considered public, the author will make an effort keep them stable, and failing that to call attention to changes. Nothing is exported by default, though all the public subroutines are exportable, either by name or by using the :all tag. The following subroutines should be considered public: =over =cut # 0.001 18-Sep-2007 T. R. Wyant # Initial release. # 0.001_01 01-Apr-2009 T. R. Wyant # Make Perl::Critic compliant (to -stern, with my own profile) # 0.002 02-Apr-2009 T. R. Wyant # Production version. # 0.002_01 07-Apr-2009 T. R. Wyant # Use $self->_build_hash(), so that we test it. package Win32::Process::Info::PT; use strict; use warnings; use base qw{Win32::Process::Info}; our $VERSION = '1.018'; use Carp; use File::Basename; use Proc::ProcessTable; # TODO figure out what we need to do here. my %_transform = ( ## CreationDate => \&Win32::Process::Info::_date_to_time_t, KernelModeTime => \&Win32::Process::Info::_clunks_to_desired, UserModeTime => \&Win32::Process::Info::_clunks_to_desired, ); my %lglarg = map {($_, 1)} qw{assert_debug_priv variant}; sub new { my $class = shift; $class = ref $class if ref $class; my $arg = shift; if (ref $arg eq 'HASH') { my @ilg = grep {!$lglarg{$_}} keys %$arg; @ilg and croak "Error - Win32::Process::Info::PT argument(s) (@ilg) illegal"; } else { croak "Error - Win32::Process::Info::PT does not support remote operation." if $arg; } no warnings qw{once}; my $self = {%Win32::Process::Info::static}; use warnings qw{once}; delete $self->{variant}; $self->{_xfrm} = \%_transform; bless $self, $class; return $self; } =item @info = $pi->GetProcInfo (); This method returns a list of anonymous hashes, each containing information on one process. If no arguments are passed, the list represents all processes in the system. You can pass a list of process IDs, and get out a list of the attributes of all such processes that actually exist. If you call this method in scalar context, you get a reference to the list. What keys are available depend on the variant in use. With the PT variant you can hope to get at most the following keys. The caveat is that the Win32::Process::Info keys are derived from Proc::ProcessTable::Process fields, and if your OS does not support the underlying field, you will not get it. Here are the possible keys and the fields from which they are derived: CreationDate: start Description: cmndline ExecutablePath: fname (note 1) KernelModeTime: stime (note 2) Name: basename (fname) Owner: '\' . getpwuid (uid) (note 3) OwnerSid: uid (note 4) ParentProcessId: ppid ProcessId: pid UserModeTime: utime (note 2) Notes: 1) ExecutablePath may not be an absolute pathname. 2) We assume that Proc::ProcessTable::Process returns stime and utime in microseconds, and multiply by 10 to get clunks. This may be wrong under some operating systems. 3) Owner has a backslash prefixed because Windows returns domain\user. I don't see a good way to get domain, but I wanted to be consistent (read: I was too lazy to special-case the test script). 4) Note that under Cygwin this is B the same as the Windows PID, which is returned in field 'winpid'. But the Subprocesses method needs the ProcessId and ParentProcessId to be consistent, and there was no documented 'winppid' field. The output will contain all processes for which information was requested, but will not necessarily contain all information for all processes. The _status key of the process hash contains the status of GetProcInfo's request(s) for information. In the case of Win32::Process::Info::PT, this will always be 0, but is provided to be consistent with the other variants. =cut { my %pw_uid; my %fld_map = ( cmndline => 'Description', fname => sub { my ($info, $proc) = @_; $info->{Name} = basename ( $info->{ExecutablePath} = $proc->fname ()); }, pid => 'ProcessId', ppid => 'ParentProcessId', start => 'CreationDate', ## stime => 'KernelModeTime', ## utime => 'UserModeTime', stime => sub { my ($info, $proc) = @_; $info->{KernelModeTime} = $proc->stime() * 10; }, utime => sub { my ($info, $proc) = @_; $info->{UserModeTime} = $proc->utime() * 10; }, uid => sub { my ($info, $proc) = @_; $info->{OwnerSid} = my $uid = $proc->uid (); $info->{Owner} = $pw_uid{$uid} ||= '\\' . getpwuid($uid); }, ); my @fld_sup = grep { defined $_ } Proc::ProcessTable->new ()->fields (); sub GetProcInfo { my ($self, @args) = @_; my $opt = ref $args[0] eq 'HASH' ? shift @args : {}; my $tbl = Proc::ProcessTable->new ()->table (); if (@args) { my %filter = map {(($_ eq '.' ? $$ : $_), 1)} @args; $tbl = [grep {$filter{$_->pid ()}} @$tbl]; } my @pinf; foreach my $proc (@$tbl) { my $info = {_status => 0}; foreach my $key (@fld_sup) { my $name = $fld_map{$key} or next; if (ref $name eq 'CODE') { $name->($info, $proc); } else { # Yes, we could just plop the information into the # hash. But _build_hash() needs to be called in # every variant so it gets tested under any # variant. $self->_build_hash($info, $name, $proc->$key()); } } push @pinf, $info; } return wantarray ? @pinf : \@pinf; } } =item @pids = $pi->ListPids () This subroutine returns a list of all known process IDs in the system, in no particular order. If called in list context, the list of process IDs itself is returned. In scalar context, a reference to the list is returned. =cut sub ListPids { my ($self, @args) = @_; my $tbl = Proc::ProcessTable->new ()->table (); my @pids; if (@args) { my %filter = map {(($_ eq '.' ? $$ : $_), 1)} @args; @pids = grep {$filter{$_}} map {$_->pid} @$tbl; } else { @pids = map {$_->pid} @$tbl; } return wantarray ? @pids : \@pids; } =back =head1 REQUIREMENTS This library uses the following libraries: Carp Time::Local Proc::ProcessTable As of this writing, all but Proc::ProcessTable are part of the standard Perl distribution. =head1 ACKNOWLEDGMENTS This module would not exist without the following people Dan Urist, author (or at least coordinator) of the Proc::ProcessTable module, upon which this is based. Jenda Krynicky, whose "How2 create a PPM distribution" (F) gave me a leg up on both PPM and tar distributions. =head1 AUTHOR Thomas R. Wyant, III (F) =head1 COPYRIGHT AND LICENSE Copyright (C) 2007, 2009-2011 by Thomas R. Wyant, III This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES. This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. =cut # ex: set textwidth=72 : 1;