File Coverage

blib/lib/Win32/Process/Info.pm
Criterion Covered Total %
statement 51 209 24.4
branch 11 114 9.6
condition 1 27 3.7
subroutine 12 23 52.1
pod 9 9 100.0
total 84 382 21.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Win32::Process::Info - Provide process information for Windows 32 systems.
4              
5             =head1 SYNOPSIS
6              
7             use Win32::Process::Info;
8             $pi = Win32::Process::Info->new ();
9             $pi->Set (elapsed_in_seconds => 0); # In clunks, not seconds.
10             @pids = $pi->ListPids (); # Get all known PIDs
11             @info = $pi->GetProcInfo (); # Get the max
12             %subs = $pi->Subprocesses (); # Figure out subprocess relationships.
13             @info = grep {
14             defined $_->{Name} &&
15             $_->{Name} =~ m/perl/
16             } $pi->GetProcInfo (); # All processes with 'perl' in name.
17              
18             =head1 NOTICE
19              
20             This package covers a multitude of sins - as many as Microsoft has
21             invented ways to get process info and I have resources and gumption
22             to code. The key to this mess is the 'variant' argument to the 'new'
23             method (q.v.).
24              
25             The WMI variant has various problems, known or suspected to be inherited
26             from Win32::OLE. See L for the gory details. The worst of these
27             is that if you use fork(), you B disallow WMI completely by
28             loading this module as follows:
29              
30             use Win32::Process::Info qw{NT};
31              
32             This method of controlling things must be considered experimental until
33             I can confirm it causes no unexpected insurmountable problems. If I am
34             forced to change it, the change will be flagged prominently in the
35             documentation.
36              
37             This change is somewhat incompatible with 1.006 and earlier because it
38             requires the import() method to be called in the correct place with the
39             correct arguments. If you C, you B
40             explicitly call Win32::Process::Info->import().
41              
42             See the import() documentation below for the details.
43              
44             B
45              
46             =head1 DESCRIPTION
47              
48             The main purpose of the Win32::Process::Info package is to get whatever
49             information is convenient (for the author!) about one or more Windows
50             32 processes. L is therefore the most-important
51             method in the package. See it for more information.
52              
53             The process IDs made available are those returned by the variant in
54             use. See the documentation to the individual variants for details,
55             especially if you are a Cygwin user.
56              
57             Unless explicitly stated otherwise, modules, variables, and so
58             on are considered private. That is, the author reserves the right
59             to make arbitrary changes in the way they work, without telling
60             anyone. For methods, variables, and so on which are considered
61             public, the author will make an effort keep them stable, and failing
62             that to call attention to changes.
63              
64             The following methods should be considered public:
65              
66             =over 4
67              
68             =cut
69              
70             package Win32::Process::Info;
71              
72 1     1   1608 use 5.006;
  1         4  
  1         49  
73              
74 1     1   5 use strict;
  1         2  
  1         43  
75 1     1   12 use warnings;
  1         2  
  1         49  
76              
77             our $VERSION = '1.021';
78              
79 1     1   3 use Carp;
  1         1  
  1         63  
80 1     1   4 use File::Spec;
  1         1  
  1         20  
81 1     1   484 use Time::Local;
  1         1288  
  1         520  
82              
83             our %static = (
84             elapsed_in_seconds => 1,
85             variant => $ENV{PERL_WIN32_PROCESS_INFO_VARIANT},
86             );
87              
88             # The real reason for the %variant_support hash is to deal with
89             # the apparant inability of Win32::API to be 'require'-d anywhere
90             # but in a BEGIN block. The 'unsupported' key is intended to be
91             # used as a 'necessary but not required' criterion; that is, if
92             # 'unsupported' is true, there's no reason to bother; but if it's
93             # false, there may still be problems of some sort. This is par-
94             # ticularly true of WMI, where the full check is rather elephan-
95             # tine.
96             #
97             # The actual 'necessary but not required' check has moved to
98             # {check_support}, with {unsupported} simply holding the result of
99             # the check. The {check_support} key is code to be executed when
100             # the import() hook is called when the module is loaded.
101             #
102             # While I was at it, I decided to consolidate all the variant-
103             # specific information in one spot and, while I was at it, write
104             # a variant checker utility.
105              
106             my %variant_support;
107             BEGIN {
108             # Cygwin has its own idea of what a process ID is, independent of
109             # the underlying operating system. The Cygwin Perl implements this,
110             # so if we're Cygwin we need to compensate. This MUST return the
111             # Windows-native form under Cygwin, which means any variant which
112             # needs another form must override.
113              
114 1 50   1   3 if ( $^O eq 'cygwin' ) {
115             *My_Pid = sub {
116 0         0 return Cygwin::pid_to_winpid( $$ );
117 0         0 };
118             } else {
119             *My_Pid = sub {
120 0     0   0 return $$;
121 1         4 };
122             }
123             %variant_support = (
124             NT => {
125             check_support => sub {
126 1         2 local $@;
127 1 50       1 eval {
128 1         155 require Win32;
129 0 0       0 Win32->can( 'IsWinNT' ) && Win32::IsWinNT();
130             } or return "$^O is not a member of the Windows NT family";
131 0 0       0 eval { require Win32::API; 1 }
  0         0  
  0         0  
132             or return 'I can not find Win32::API';
133 0         0 my @path = File::Spec->path();
134             DLL_LOOP:
135 0         0 foreach my $dll (qw{PSAPI.DLL ADVAPI32.DLL KERNEL32.DLL}) {
136 0         0 foreach my $loc (@path) {
137 0 0       0 next DLL_LOOP if -e File::Spec->catfile ($loc, $dll);
138             }
139 0         0 return "I can not find $dll";
140             }
141 0         0 return 0;
142             },
143             make => sub {
144 0         0 require Win32::Process::Info::NT;
145 0         0 Win32::Process::Info::NT->new (@_);
146             },
147 1         12 unsupported => "Disallowed on load of @{[__PACKAGE__]}.",
148             },
149             PT => {
150             check_support => sub {
151 1         1 local $@;
152 1         157 return "Unable to load Proc::ProcessTable"
153 1 50       1 unless eval {require Proc::ProcessTable; 1};
  0         0  
154 0         0 return 0;
155             },
156             make => sub {
157 0         0 require Win32::Process::Info::PT;
158 0         0 Win32::Process::Info::PT->new (@_);
159             },
160 1         7 unsupported => "Disallowed on load of @{[__PACKAGE__]}.",
161             },
162             WMI => {
163             check_support => sub {
164 1         1 local $@;
165 1 50       2 _isReactOS()
166             and return 'Unsupported under ReactOS';
167 1 50       1 eval {
168 1         1170 require Win32::OLE;
169 0         0 1;
170             } or return 'Unable to load Win32::OLE';
171 0         0 my ( $wmi, $proc );
172 0         0 my $old_warn = Win32::OLE->Option( 'Warn' );
173 0         0 eval {
174 0         0 Win32::OLE->Option( Warn => 0 );
175 0         0 $wmi = Win32::OLE->GetObject(
176             'winmgmts:{impersonationLevel=impersonate,(Debug)}!//./root/cimv2'
177             );
178 0 0       0 $wmi and $proc = $wmi->Get(
179             sprintf q{Win32_Process='%s'}, __PACKAGE__->My_Pid()
180             );
181             };
182 0         0 Win32::OLE->Option( Warn => $old_warn );
183 0 0       0 $wmi or return 'Unable to get WMI object';
184 0 0       0 $proc or return 'WMI broken: unable to get process object';
185 0         0 return 0;
186             },
187             make => sub {
188 0         0 require Win32::Process::Info::WMI;
189 0         0 Win32::Process::Info::WMI->new (@_);
190             },
191 1         4 unsupported => "Disallowed on load of @{[__PACKAGE__]}.",
  1         1548  
192             },
193             );
194             }
195              
196             our %mutator = (
197             elapsed_in_seconds => sub {$_[2]},
198             variant => sub {
199             ref $_[0]
200             and eval { $_[0]->isa( 'Win32::Process::Info' ) }
201             or croak 'Variant can not be set on an instance';
202             foreach (split '\W+', $_[2]) {
203             my $status;
204             $status = variant_support_status( $_ )
205             and croak "Variant '$_' unsupported on your configuration; ",
206             $status;
207             }
208             $_[2]
209             },
210             );
211              
212              
213             =item $pi = Win32::Process::Info->new ([machine], [variant], [hash])
214              
215             This method instantiates a process information object, connected
216             to the given machine, and using the given variant.
217              
218             The following variants are currently supported:
219              
220             NT - Uses the NT-native mechanism. Good on any NT, including
221             Windows 2000. This variant does not support connecting to
222             another machine, so the 'machine' argument must be an
223             empty string (or undef, if you prefer).
224              
225             PT - Uses Dan Urist's Proc::ProcessTable, making it possible
226             (paradoxically) to use this module on other operating systems than
227             Windows. Only those Proc::ProcessTable::Process fields which seem
228             to correspond to WMI items are returned. B the PT variant
229             is to be considered experimental, and may be changed or retracted
230             in future releases.
231              
232             WMI - Uses the Windows Management Implementation. Good on Win2K, ME,
233             and possibly others, depending on their vintage and whether
234             WMI has been retrofitted.
235              
236             The initial default variant comes from environment variable
237             PERL_WIN32_PROCESS_INFO_VARIANT. If this is not found, it will be
238             'WMI,NT,PT', which means to try WMI first, NT if WMI fails, and PT as a
239             last resort. This can be changed using Win32::Process::Info->Set
240             (variant => whatever).
241              
242             The hash argument is a hash reference to additional arguments, if
243             any. The hash reference can actually appear anywhere in the argument
244             list, though positional arguments are illegal after the hash reference.
245              
246             The following hash keys are supported:
247              
248             variant => corresponds to the 'variant' argument (all)
249             assert_debug_priv => assert debug if available (all) This
250             only has effect under WMI. The NT variant always
251             asserts debug. You want to be careful doing this
252             under WMI if you're fetching the process owner
253             information, since the script can be badly behaved
254             (i.e. die horribly) for those processes whose
255             ExecutablePath is only available with the debug
256             privilege turned on.
257             host => corresponds to the 'machine' argument (WMI)
258             user => username to perform operation under (WMI)
259             password => password corresponding to the given
260             username (WMI)
261              
262             ALL hash keys are optional. SOME hash keys are only supported under
263             certain variants. These are indicated in parentheses after the
264             description of the key. It is an error to specify a key that the
265             variant in use does not support.
266              
267             =cut
268              
269             my @argnam = qw{host variant};
270             sub new {
271 0     0 1 0 my ($class, @params) = @_;
272 0 0       0 $class = ref $class if ref $class;
273 0         0 my %arg;
274 0         0 my ( $self, @probs );
275              
276 0         0 my $inx = 0;
277 0         0 foreach my $inp (@params) {
278 0 0       0 if (ref $inp eq 'HASH') {
    0          
    0          
279 0         0 foreach my $key (keys %$inp) {$arg{$key} = $inp->{$key}}
  0         0  
280             } elsif (ref $inp) {
281 0         0 croak "Argument may not be @{[ref $inp]} reference.";
  0         0  
282             } elsif ($argnam[$inx]) {
283 0         0 $arg{$argnam[$inx]} = $inp;
284             } else {
285 0         0 croak "Too many positional arguments.";
286             }
287 0         0 $inx++;
288             }
289              
290             _import_done()
291 0 0       0 or croak __PACKAGE__,
292             '->import() must be called before calling ', __PACKAGE__,
293             '->new()';
294 0 0       0 my $mach = $arg{host} or delete $arg{host};
295 0   0     0 my $try = $arg{variant} || $static{variant} || 'WMI,NT,PT';
296 0         0 foreach my $variant (grep {$_} split '\W+', $try) {
  0         0  
297 0         0 my $status;
298 0 0       0 $status = variant_support_status( $variant ) and do {
299 0         0 push @probs, $status;
300 0         0 next;
301             };
302 0         0 my $self;
303 0 0       0 $self = $variant_support{$variant}{make}->( \%arg ) and do {
304 0   0     0 $static{variant} ||= $self->{variant} = $variant;
305             };
306 0         0 return $self;
307             }
308 0         0 croak join '; ', @probs;
309             }
310              
311             =item @values = $pi->Get (attributes ...)
312              
313             This method returns the values of the listed attributes. If
314             called in scalar context, it returns the value of the first
315             attribute specified, or undef if none was. An exception is
316             raised if you specify a non-existent attribute.
317              
318             This method can also be called as a class method (that is, as
319             Win32::Process::Info->Get ()) to return default attributes values.
320              
321             The relevant attribute names are:
322              
323             B is TRUE to convert elapsed user and
324             kernel times to seconds. If FALSE, they are returned in
325             clunks (that is, hundreds of nanoseconds). The default is
326             TRUE.
327              
328             B is the variant of the Process::Info code in use,
329             and should be zero or more of 'WMI' or 'NT', separated by
330             commas. 'WMI' selects the Windows Management Implementation, and
331             'NT' selects the Windows NT native interface.
332              
333             B is the name of the machine connected to. This is
334             not available as a class attribute.
335              
336             =cut
337              
338             sub Get {
339 0     0 1 0 my ($self, @args) = @_;
340 0 0       0 $self = \%static unless ref $self;
341 0         0 my @vals;
342 0         0 foreach my $name (@args) {
343 0 0       0 croak "Error - Attribute '$name' does not exist."
344             unless exists $self->{$name};
345 0 0       0 croak "Error - Attribute '$name' is private."
346             if $name =~ m/^_/;
347 0         0 push @vals, $self->{$name};
348             }
349 0 0       0 return wantarray ? @vals : $vals[0];
350             }
351              
352             =item @values = $pi->Set (attribute => value ...)
353              
354             This method sets the values of the listed attributes,
355             returning the values of all attributes listed if called in
356             list context, or of the first attribute listed if called
357             in scalar context.
358              
359             This method can also be called as a class method (that is, as
360             Win32::Process::Info->Set ()) to change default attribute values.
361              
362             The relevant attribute names are the same as for Get.
363             However:
364              
365             B is read-only at the instance level. That is,
366             Win32::Process::Info->Set (variant => 'NT') is OK, but
367             $pi->Set (variant => 'NT') will raise an exception. If
368             you set B to an empty string (the default), the
369             next "new" will iterate over all possibilities (or the
370             contents of environment variable
371             PERL_WIN32_PROCESS_INFO_VARIANT if present), and set
372             B to the first one that actually works.
373              
374             B is not available as a class attribute, and is
375             read-only as an instance attribute. It is B useful for
376             discovering your machine name - if you instantiated the
377             object without specifying a machine name, you will get
378             nothing useful back.
379              
380             =cut
381              
382             sub Set {
383 0     0 1 0 my ($self, @args) = @_;
384 0 0       0 croak "Error - Set requires an even number of arguments."
385             if @args % 2;
386 0 0       0 $self = \%static unless ref $self;
387 0   0     0 my $mutr = $self->{_mutator} || \%mutator;
388 0         0 my @vals;
389 0         0 while (@args) {
390 0         0 my $name = shift @args;
391 0         0 my $val = shift @args;
392 0 0       0 croak "Error - Attribute '$name' does not exist."
393             unless exists $self->{$name};
394 0 0       0 croak "Error - Attribute '$name' is read-only."
395             unless exists $mutr->{$name};
396 0         0 $self->{$name} = $mutr->{$name}->($self, $name, $val);
397 0         0 push @vals, $self->{$name};
398             }
399 0 0       0 return wantarray ? @vals : $vals[0];
400             }
401              
402             =item @pids = $pi->ListPids ();
403              
404             This method lists all known process IDs in the system. If
405             called in scalar context, it returns a reference to the
406             list of PIDs. If you pass in a list of pids, the return will
407             be the intersection of the argument list and the actual PIDs
408             in the system.
409              
410             =cut
411              
412             sub ListPids {
413 0     0 1 0 confess
414             "Error - Whoever coded this forgot to override ListPids.";
415             }
416              
417             =item @info = $pi->GetProcInfo ();
418              
419             This method returns a list of anonymous hashes, each containing
420             information on one process. If no arguments are passed, the
421             list represents all processes in the system. You can pass a
422             list of process IDs, and get out a list of the attributes of
423             all such processes that actually exist. If you call this
424             method in scalar context, you get a reference to the list.
425              
426             What keys are available depends on the variant in use.
427             You can hope to get at least the following keys for a
428             "normal" process (i.e. not the idle process, which is PID 0,
429             nor the system, which is some small indeterminate PID) to
430             which you have access:
431              
432             CreationDate
433             ExecutablePath
434             KernelModeTime
435             MaximumWorkingSetSize
436             MinimumWorkingSetSize
437             Name (generally the name of the executable file)
438             ProcessId
439             UserModeTime
440              
441             You may find other keys available as well, depending on which
442             operating system you're using, and which variant of Process::Info
443             you're using.
444              
445             This method also optionally takes as its first argument a reference
446             to a hash of option values. The only supported key is:
447              
448             no_user_info => 1
449             Do not return keys Owner and OwnerSid, even if available.
450             These tend to be time-consuming, and can cause problems
451             under the WMI variant.
452              
453             =cut
454              
455             sub GetProcInfo {
456 0     0 1 0 confess
457             "Programming Error - Whoever coded this forgot to override GetProcInfo.";
458             }
459              
460             =item Win32::Process::Info->import ()
461              
462             The purpose of this static method is to specify which variants of the
463             functionality are legal to use. Possible arguments are 'NT', 'WMI',
464             'PT', or some combination of these (e.g. ('NT', 'WMI')). Unrecognized
465             arguments are ignored, though this may change if this class becomes a
466             subclass of Exporter. If called with no arguments, it is as though it
467             were called with arguments ('NT', 'WMI', 'PT'). See L, below, for
468             why this mess was introduced in the first place.
469              
470             This method must be called at least once, B, or B
471             variants will be legal to use. Usually it does B need to be
472             explicitly called by the user, since it is called implicitly when you
473             C. If you C
474             you B have to call this method explicitly.
475              
476             If this method is called more than once, the second and subsequent calls
477             will have no effect on what variants are available. The reason for this
478             will be made clear (I hope!) under L, below.
479              
480             The only time a user of this module needs to do anything different
481             versus version 1.006 and previous of this module is if this module is
482             being loaded in such a way that this method is not implicitly called.
483             This can happen two ways:
484              
485             use Win32::Process::Info ();
486              
487             explicitly bypasses the implicit call of this method. Don't do that.
488              
489             require Win32::Process::Info;
490              
491             also does not call this method. If you must load this module using
492             require rather than use, follow the require with
493              
494             Win32::Process::Info->import ();
495              
496             passing any necessary arguments.
497              
498             =cut
499              
500             { # Begin local symbol block.
501              
502             my $idempotent;
503              
504             sub import { ## no critic (RequireArgUnpacking)
505 1     1   325 my ($pkg, @params) = @_;
506 1         1 my (@args, @vars);
507 1         3 foreach (@params) {
508 0 0       0 if (exists $variant_support{$_}) {
509 0         0 push @vars, $_;
510             } else {
511 0         0 push @args, $_;
512             }
513             }
514              
515 1 50       4 if ($idempotent++) {
516             # Warning here maybe?
517             } else {
518 1 50       6 @vars or push @vars, keys %variant_support;
519 1         1 foreach my $try (@vars) {
520 3 50       7 $variant_support{$try} or next;
521 3   33     2 $variant_support{$try}{unsupported} = eval {
522             $variant_support{$try}{check_support}->()} || $@;
523             }
524             }
525              
526 1         3 return;
527              
528             # Do this if we become a subclass of Exporter
529             # @_ = ( $pkg, @args );
530             # goto &Exporter::import;;
531             }
532              
533             # Return the number of times import() done.
534             sub _import_done {
535 3     3   7 return $idempotent;
536             }
537              
538             } # End local symbol block.
539              
540              
541             {
542             my $is_reactos = $^O eq 'MSWin32' &&
543             defined $ENV{OS} && lc $ENV{OS} eq 'reactos';
544             sub _isReactOS {
545 1     1   2 return $is_reactos;
546             }
547             }
548              
549              
550             =item %subs = $pi->Subprocesses ([pid ...])
551              
552             This method takes as its argument a list of PIDs, and returns a hash
553             indexed by PID and containing, for each PID, a reference to a list of
554             all subprocesses of that process. If those processes have subprocesses
555             as well, you will get the sub-sub processes, and so ad infinitum, so
556             you may well get back more hash keys than you passed process IDs. Note
557             that the process of finding the sub-sub processes is iterative, not
558             recursive; so you don't get back a tree.
559              
560             If no argument is passed, you get all processes in the system.
561              
562             If called in scalar context you get a reference to the hash.
563              
564             This method works off the ParentProcessId attribute. Not all variants
565             support this. If the variant you're using doesn't support this
566             attribute, you get back an empty hash. Specifically:
567              
568             NT -> unsupported
569             PT -> supported
570             WMI -> supported
571              
572             =cut
573              
574             sub Subprocesses {
575 0     0 1 0 my ($self, @args) = @_;
576 0         0 my %prox = map {($_->{ProcessId} => $_)}
  0         0  
577 0         0 @{$self->GetProcInfo ({no_user_info => 1})};
578 0         0 my %subs;
579 0         0 my $rslt = \%subs;
580 0         0 my $key_found;
581 0         0 foreach my $proc (values %prox) {
582 0   0     0 $subs{$proc->{ProcessId}} ||= [];
583             # TRW 1.011_01 next unless $proc->{ParentProcessId};
584 0 0       0 defined (my $pop = $proc->{ParentProcessId}) or next; # TRW 1.011_01
585 0         0 $key_found++;
586             # TRW 1.011_01 next unless $prox{$proc->{ParentProcessId}};
587 0 0       0 $prox{$pop} or next; # TRW 1.011_01
588             # TRW 1.012_02 $proc->{CreationDate} >= $prox{$pop}{CreationDate} or next; # TRW 1.011_01
589 0 0 0     0 (defined($proc->{CreationDate}) &&
      0        
590             defined($prox{$pop}{CreationDate}) &&
591             $proc->{CreationDate} >= $prox{$pop}{CreationDate})
592             or next; # TRW 1.012_02
593             # TRW 1.011_01 push @{$subs{$proc->{ParentProcessId}}}, $proc->{ProcessId};
594 0         0 push @{$subs{$pop}}, $proc->{ProcessId};
  0         0  
595             }
596 0         0 my %listed;
597 0 0       0 return %listed unless $key_found;
598 0 0       0 if (@args) {
599 0         0 $rslt = \%listed;
600 0         0 while (@args) {
601 0         0 my $pid = shift @args;
602 0 0       0 next unless $subs{$pid}; # TRW 1.006
603 0 0       0 next if $listed{$pid};
604 0         0 $listed{$pid} = $subs{$pid};
605 0         0 push @args, @{$subs{$pid}};
  0         0  
606             }
607             }
608 0 0       0 return wantarray ? %$rslt : $rslt;
609             }
610              
611             =item @info = $pi->SubProcInfo ();
612              
613             This is a convenience method which wraps GetProcInfo(). It has the same
614             calling sequence, and returns generally the same data. But the data
615             returned by this method will also have the {subProcesses} key, which
616             will contain a reference to an array of hash references representing the
617             data on subprocesses of each process.
618              
619             Unlike the data returned from Subprocesses(), the data here are not
620             flattened; so if you specify one or more process IDs as arguments, you
621             will get back at most the number of process IDs you specified; fewer if
622             some of the specified processes do not exist.
623              
624             B that a given process can occur more than once in the
625             output. If you call SubProcInfo without arguments, the @info array will
626             contain every process in the system, even those which are also in some
627             other process' {subProcesses} array.
628              
629             Also unlike Subprocesses(), you will get an exception if you use this
630             method with a variant that does not support the ParentProcessId key.
631              
632             =cut
633              
634             sub SubProcInfo {
635 0     0 1 0 my ($self, @args) = @_;
636 0 0       0 my $opt = ref $args[0] eq 'HASH' ? shift @args : {};
637 0         0 my @data = $self->GetProcInfo ($opt);
638 0         0 my %subs = map {$_->{ProcessId} => $_} @data;
  0         0  
639 0         0 my $bingo;
640 0         0 foreach my $proc (@data) {
641 0 0       0 exists $proc->{ParentProcessId} or next;
642 0   0     0 $proc->{subProcesses} ||= [];
643 0         0 $bingo++;
644 0 0       0 defined (my $dad = $subs{$proc->{ParentProcessId}}) or next;
645 0 0 0     0 (defined $dad->{CreationDate} && defined $proc->{CreationDate})
646             or next;
647 0 0       0 $dad->{CreationDate} > $proc->{CreationDate} and next;
648 0   0     0 push @{$dad->{subProcesses} ||= []}, $proc;
  0         0  
649             }
650 0 0       0 $bingo or croak "Error - Variant '@{[$self->Get('variant')
  0         0  
651             ]}' does not support the ParentProcessId key";
652 0 0       0 if (@args) {
653 0 0       0 return (map {exists $subs{$_} ? $subs{$_} : ()} @args);
  0         0  
654             } else {
655 0         0 return @data;
656             }
657             }
658              
659             =item $pid = $pi->My_Pid()
660              
661             This convenience method returns the process ID of the current process,
662             in a form appropriate to the operating system and the variant in use.
663             Normally, it simply returns C<$$>. But Cygwin has its own idea of what
664             the process ID is, which may differ from Windows. Worse than that, under
665             Cygwin the NT and WMI variants return Windows PIDs, while PT appears to
666             return Cygwin PIDs.
667              
668             =cut
669              
670             # This is defined above, trickily, as an assignment to *My_Pid, so we
671             # don't have to test $^O every time. It's above because code in a BEGIN
672             # block needs it.
673              
674             =item $text = Win32::Process::Info->variant_support_status($variant);
675              
676             This static method returns the support status of the given variant. The
677             return is false if the variant is supported, or an appropriate message
678             if the variant is unsupported.
679              
680             This method can also be called as a normal method, or even as a
681             subroutine.
682              
683             =cut
684              
685             sub variant_support_status {
686 3     3 1 1539 my @args = @_;
687 3 50       8 my $variant = pop @args or croak "Variant not specified";
688 3 50       7 exists $variant_support{$variant}
689             or croak "Variant '$variant' is unknown";
690 3 50       4 _import_done()
691             or croak __PACKAGE__,
692             '->import() must be called before calling ', __PACKAGE__,
693             '->variant_support_status()';
694 3         8 return $variant_support{$variant}{unsupported};
695             }
696              
697             =item print "$pi Version = @{[$pi->Version ()]}\n"
698              
699             This method just returns the version number of the
700             Win32::Process::Info object.
701              
702             =cut
703              
704             sub Version {
705 1     1 1 8 return $Win32::Process::Info::VERSION;
706             }
707              
708             #
709             # $self->_build_hash ([hashref], key, value ...)
710             # builds a process info hash out of the given keys and values.
711             # The keys are assumed to be the WMI keys, and will be trans-
712             # formed if needed. The values will also be transformed if
713             # needed. The resulting hash entries will be placed into the
714             # given hash if one is present, or into a new hash if not.
715             # Either way, the hash is returned.
716              
717             sub _build_hash {
718 0     0     my ($self, $hash, @args) = @_;
719 0   0       $hash ||= {};
720 0           while (@args) {
721 0           my $key = shift @args;
722 0           my $val = shift @args;
723 0 0         $val = $self->{_xfrm}{$key}->($self, $val)
724             if (exists $self->{_xfrm}{$key});
725 0           $hash->{$key} = $val;
726             }
727 0           return $hash;
728             }
729              
730              
731             # $self->_clunks_to_desired (clunks ...)
732             # converts elapsed times in clunks to elapsed times in
733             # seconds, PROVIDED $self->{elapsed_in_seconds} is TRUE.
734             # Otherwise it simply returns its arguments unmodified.
735              
736             sub _clunks_to_desired {
737 0     0     my $self = shift;
738 0 0         @_ = map {defined $_ ? $_ / 10_000_000 : undef} @_ if $self->{elapsed_in_seconds};
  0 0          
739 0 0         return wantarray ? @_ : $_[0];
740             }
741              
742             # $self->_date_to_time_t (date ...)
743             # converts the input dates (assumed YYYYmmddhhMMss) to
744             # Perl internal time, returning the results. The "self"
745             # argument is unused.
746              
747              
748             sub _date_to_time_t {
749 0     0     my ($self, @args) = @_;
750 0           my @result;
751 0           local $^W = 0; # Prevent Time::Local 1.1 from complaining. This appears
752             # to be fixed in 1.11, but since Time::Local is part of
753             # the ActivePerl core, there's no PPM installer for it.
754             # At least, not that I can find.
755 0           foreach (@args) {
756 0 0         if ($_) {
757 0           my ($yr, $mo, $da, $hr, $mi, $sc) = m/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/;
758 0           --$mo;
759 0           my $val = timelocal ($sc, $mi, $hr, $da, $mo, $yr);
760 0           push @result, $val;
761             }
762             else {
763 0           push @result, undef;
764             }
765             }
766 0 0         return @result if wantarray;
767 0           return $result[0];
768             }
769              
770             1;
771             __END__