File Coverage

blib/lib/Win32/Env.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Win32::Env;
2             our $VERSION='0.03';
3            
4             =head1 NAME
5            
6             Win32::Env - set and retrieve global system and user environment variables under Win32.
7            
8             =head1 SYNOPSIS
9            
10             use Win32::Env;
11            
12             # Retrieving value
13             my $user_path=GetEnv(ENV_USER, 'PATH');
14             print $user_path;
15            
16             # Setting new value
17             SetEnv(ENV_USER, 'PATH', 'C:\\MyBin');
18            
19             # Deleting value
20             DelEnv(ENV_USER, 'PATH');
21            
22             # Retrieving list of all variables in environment
23             my @vars=ListEnv(ENV_USER);
24             print(join(', ', @vars));
25            
26             # Broadcasting message about our changes
27             BroadcastEnv();
28            
29             =cut
30            
31 2     2   48162 use warnings;
  2         7  
  2         81  
32 2     2   12 use strict;
  2         5  
  2         62  
33            
34 2     2   19 use Carp;
  2         9  
  2         177  
35 2     2   890 use Win32::TieRegistry(FixSzNulls=>1);
  0            
  0            
36            
37             =head1 NOTES
38            
39             =head2 System and user variables
40            
41             Just like many Unix shells have global defaults and user profile, Windows store
42             several sets of environment variables. Modifying system's set (see L)
43             will affect every user on system, while working with user's (see L)
44             will only affect current user.
45            
46             =head2 Fixed and variable length values
47            
48             While it is impossible to distinguish them by normal means (like C<%ENV> or C's
49             C command, variable values could be either fixed length or variable length strings.
50             Fixed length strings should always resolve to same literal value that was assigned to them, while
51             variable length strings may have references to other variables in them that in form of C<%OTHER_VAR%>
52             that should be expanded to values of that variables. Note "should". This expansion is not
53             performed by system automatically, but must be done by program that uses variable.
54            
55             =cut
56            
57             =head1 EXPORT
58            
59             SetEnv GetEnv DelEnv ListEnv BroadcastEnv ENV_USER ENV_SYSTEM
60            
61             =cut
62            
63             use Exporter qw(import);
64             our @EXPORT=qw(SetEnv GetEnv DelEnv ListEnv InsertPathEnv BroadcastEnv ENV_USER ENV_SYSTEM);
65            
66             =head1 CONSTANTS
67            
68             =head2 ENV_USER
69            
70             Used as value for C<$sys_or_usr> argument to indicate that
71             you wish to work with current user's environment.
72            
73             =head2 ENV_SYSTEM
74            
75             Used as value for C<$sys_or_usr> argument to indicate that
76             you wish to work with system's global environment.
77            
78             =cut
79            
80             use constant ENV_USER =>0;
81             use constant ENV_SYSTEM =>1;
82            
83             use constant ENVKEY_USER => 'HKEY_CURRENT_USER\\Environment';
84             use constant ENVKEY_SYSTEM => 'HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment';
85            
86             =head1 FUNCTIONS
87            
88             =cut
89            
90             sub _NWA{
91             my $lib=shift,
92             my @proto=@_;
93             require Win32::API;
94             return(new Win32::API($lib, @proto) or die "Can't import API $proto[0] from $lib: $^E\n");
95             }
96            
97             # TODO: error/sanity checks for other args
98             sub _num_to_key($){
99             my $sysusr=shift;
100             if(!defined($sysusr) or ($sysusr ne ENV_USER and $sysusr ne ENV_SYSTEM and $sysusr ne ENVKEY_USER and $sysusr ne ENVKEY_SYSTEM)){
101             local $Carp::CarpLevel=2;
102             carp((caller(1))[3], ": \$sys_or_usr argument must be either ENV_USER or ENV_SYSTEM");
103             return;
104             }
105             if($sysusr eq ENV_USER) { return ENVKEY_USER; }
106             elsif($sysusr eq ENV_SYSTEM) { return ENVKEY_SYSTEM; }
107             return $sysusr;
108             }
109            
110             sub _is_empty_var{
111             my $var=shift;
112             if(!defined($var) or $var eq ''){
113             local $Carp::CarpLevel=2;
114             carp((caller(1))[3], ": \$variable argument must be defined non-empty name");
115             return 1;
116             }
117             return;
118             }
119            
120             =head2 SetEnv($sys_or_usr, $variable, $value[, $expand])
121            
122             $success=SetEnv($sys_or_usr, $variable, $value);
123             $success=SetEnv($sys_or_usr, $variable, $value, $expand);
124            
125             Sets variable named $variable in environment selected with $sys_or_usr (L or L)
126             to specified $value. Optional $expand set to true or false value specifies if
127             value should be marked as variable length string with expandable references
128             or not. See L for details. If $expand
129             is not defined C will use default Windows behavior - any
130             value that have C<%> in it will be marked as variable length. Returns true
131             on success and false otherwise.
132            
133             =cut
134            
135             sub SetEnv{
136             my ($sysusr, $var, $value, $expand)=@_;
137             $sysusr=(_num_to_key($sysusr) or return);
138             return if _is_empty_var($var);
139             if(!defined($expand) and defined($value)){ $expand=($value=~/%/); }
140             $expand=(defined($expand) and $expand)?Win32::TieRegistry::REG_EXPAND_SZ:undef;
141             return Win32::TieRegistry->new($sysusr)->SetValue($var, $value, $expand);
142             }
143            
144             =head2 GetEnv($sys_or_usr, $variable)
145            
146             $value=GetEnv($sys_or_usr, $variable);
147             ($value, $expand)=GetEnv($sys_or_usr, $variable);
148            
149             Returns pair of value of variable named $variable from environment selected
150             with $sys_or_usr (L or L) and true or false value
151             signifying if it is should be expanded or not (see L).
152            
153             =cut
154            
155             sub GetEnv{
156             my ($sysusr, $var)=@_;
157             $sysusr=(_num_to_key($sysusr) or return);
158             return if _is_empty_var($var);
159             my($value, $type)=Win32::TieRegistry->new($sysusr)->GetValue($var);
160             return wantarray?($value, defined($type)?$type==Win32::TieRegistry::REG_EXPAND_SZ:undef):$value;
161             }
162            
163             =head2 DelEnv($sys_or_usr, $variable)
164            
165             DelEnv($sys_or_usr, $variable)
166            
167             Deletes variable named $variable from environment selected with $sys_or_usr
168             (L or L).
169            
170             =cut
171            
172             sub DelEnv{
173             my ($sysusr, $var)=@_;
174             $sysusr=(_num_to_key($sysusr) or return);
175             return if _is_empty_var($var);
176             Win32::TieRegistry->new($sysusr)->RegDeleteValue($var);
177             }
178            
179             =head2 ListEnv($sys_or_usr)
180            
181             @list_of_variables=ListEnv($sys_or_usr);
182            
183             Returns list of all variables in environment selected with $sys_or_usr
184             (L or L).
185            
186             =cut
187            
188             sub ListEnv{
189             my ($sysusr, $var)=@_;
190             $sysusr=(_num_to_key($sysusr) or return);
191             return Win32::TieRegistry->new($sysusr)->ValueNames;
192             }
193            
194             =head2 InsertPathEnv($sys_or_usr, $variable, $path[, $path_separator])
195            
196             $success=InsertPathEnv($sys_or_usr, $variable, $path);
197             $success=InsertPathEnv($sys_or_usr, $variable, $path[, $path_separator]);
198            
199             One of common use of enviroment variables is to store path lists to binary, library and
200             other directories like this. This function allows you to insert a path in such a variable.
201             Typical usage in some kind of installation script could be like this:
202            
203             InsertPathEnv(ENV_SYSTEM, PATH => $bindir);
204             InsertPathEnv(ENV_SYSTEM, PERL5LIB => $libdir);
205             BroadcastEnv();
206            
207             Path specified with $path will be added to $variable from environment selected with $sys_or_usr
208             (L or L), using $path_separator as separators for elements on parse
209             and inserting. If you do not specify a $path_separator, default system path separator
210             will be detected with C module. Function returns false on failure, and true
211             on success with true value being one of '1' for successful insert or '2' if specified $path
212             already present in $variable.
213            
214             =cut
215            
216             sub InsertPathEnv{
217             my($sysusr, $var, $path, $psep)=@_;
218             $sysusr=(_num_to_key($sysusr) or return);
219             return if _is_empty_var($var);
220             unless(defined($path) and $path ne ''){ return; }
221             if(!defined($psep)){ require Config; $psep=$Config::Config{'path_sep'}; }
222            
223             $path=~s/\//\\/g;
224             my $elements=(GetEnv($sysusr, $var) or '');
225            
226             my @elements=split($psep, $elements);
227             my $found=0;
228            
229             foreach(@elements){
230             $_=~s/[\\\/]$//;
231             if(lc($_) eq lc($path)){
232             return 2;
233             }
234             }
235             unless(SetEnv($sysusr, $var, join($psep, @elements, $path))) { return; }
236             return 1;
237             }
238            
239             =head2 BroadcastEnv()
240            
241             BroadcastEnv();
242            
243             Broadcasts system message that environment has changed. This will make system processes responsible for
244             environment aware of change, otherwise your changes will be noticed only on next reboot. Note that most
245             user programs or still won't see changes until next run and neither will their children, as they get environment
246             from their parents. Your changes also will not be available in C<%ENV> to either your process or
247             any processes you spawn. Assign to C<%ENV> yourself in addition to C if need it.
248            
249             =cut
250            
251             sub BroadcastEnv(){
252             use constant HWND_BROADCAST => 0xffff;
253             use constant WM_SETTINGCHANGE => 0x001A;
254             # SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
255             my $SendMessage=_NWA('user32', 'SendMessage', 'LLPP', 'L');
256             $SendMessage->Call(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 'Environment');
257             }
258            
259             1;
260            
261             =head1 AUTHOR
262            
263             Oleg "Rowaa[SR13]" V. Volkov, C<>
264            
265             =head1 BUGS
266            
267             Please report any bugs or feature requests to
268             C, or through the web interface at
269             L.
270             I will be notified, and then you'll automatically be notified of progress on
271             your bug as I make changes.
272            
273             =head1 SUPPORT
274            
275             You can find documentation for this module with the perldoc command.
276            
277             perldoc Win32::Env
278            
279             You can also look for information at:
280            
281             =over 4
282            
283             =item * AnnoCPAN: Annotated CPAN documentation
284            
285             L
286            
287             =item * CPAN Ratings
288            
289             L
290            
291             =item * RT: CPAN's request tracker
292            
293             L
294            
295             =item * Search CPAN
296            
297             L
298            
299             =back
300            
301             =head1 COPYRIGHT & LICENSE
302            
303             Copyright 2006 Oleg "Rowaa[SR13]" V. Volkov, all rights reserved.
304            
305             This program is free software; you can redistribute it and/or modify it
306             under the same terms as Perl itself.
307            
308             =cut