| 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
|
|
1045
|
use 5.006; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
29
|
|
|
73
|
|
|
|
|
|
|
|
|
74
|
1
|
|
|
1
|
|
3
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
25
|
|
|
75
|
1
|
|
|
1
|
|
10
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
32
|
|
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
our $VERSION = '1.022'; |
|
78
|
|
|
|
|
|
|
|
|
79
|
1
|
|
|
1
|
|
3
|
use Carp; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
50
|
|
|
80
|
1
|
|
|
1
|
|
3
|
use File::Spec; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
14
|
|
|
81
|
1
|
|
|
1
|
|
407
|
use Time::Local; |
|
|
1
|
|
|
|
|
1021
|
|
|
|
1
|
|
|
|
|
450
|
|
|
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
|
|
|
|
|
6
|
}; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
%variant_support = ( |
|
124
|
|
|
|
|
|
|
NT => { |
|
125
|
|
|
|
|
|
|
check_support => sub { |
|
126
|
1
|
|
|
|
|
1
|
local $@; |
|
127
|
1
|
50
|
|
|
|
1
|
eval { |
|
128
|
1
|
|
|
|
|
127
|
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
|
|
|
|
|
8
|
unsupported => "Disallowed on load of @{[__PACKAGE__]}.", |
|
148
|
|
|
|
|
|
|
}, |
|
149
|
|
|
|
|
|
|
PT => { |
|
150
|
|
|
|
|
|
|
check_support => sub { |
|
151
|
1
|
|
|
|
|
1
|
local $@; |
|
152
|
1
|
|
|
|
|
206
|
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
|
|
|
|
|
8
|
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
|
|
|
|
|
204
|
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
|
|
|
|
|
3
|
unsupported => "Disallowed on load of @{[__PACKAGE__]}.", |
|
|
1
|
|
|
|
|
1237
|
|
|
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 |
|
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
|
|
292
|
my ($pkg, @params) = @_; |
|
506
|
1
|
|
|
|
|
1
|
my (@args, @vars); |
|
507
|
1
|
|
|
|
|
2
|
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
|
|
|
|
5
|
@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
|
|
|
3
|
$variant_support{$try}{unsupported} = eval { |
|
522
|
|
|
|
|
|
|
$variant_support{$try}{check_support}->()} || $@; |
|
523
|
|
|
|
|
|
|
} |
|
524
|
|
|
|
|
|
|
} |
|
525
|
|
|
|
|
|
|
|
|
526
|
1
|
|
|
|
|
2
|
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
|
|
6
|
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
|
|
4
|
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
|
1991
|
my @args = @_; |
|
687
|
3
|
50
|
|
|
|
10
|
my $variant = pop @args or croak "Variant not specified"; |
|
688
|
3
|
50
|
|
|
|
6
|
exists $variant_support{$variant} |
|
689
|
|
|
|
|
|
|
or croak "Variant '$variant' is unknown"; |
|
690
|
3
|
50
|
|
|
|
5
|
_import_done() |
|
691
|
|
|
|
|
|
|
or croak __PACKAGE__, |
|
692
|
|
|
|
|
|
|
'->import() must be called before calling ', __PACKAGE__, |
|
693
|
|
|
|
|
|
|
'->variant_support_status()'; |
|
694
|
3
|
|
|
|
|
7
|
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
|
7
|
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__ |