File Coverage

blib/lib/Win32/SystemInfo.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Win32::SystemInfo;
2            
3             require 5.8.0;
4 1     1   903 use strict;
  1         2  
  1         40  
5 1     1   6 use warnings;
  1         2  
  1         4745  
6 1     1   2032 use Win32::API 0.60;
  0            
  0            
7             use Win32::TieRegistry qw(:KEY_);
8            
9             use vars qw($VERSION);
10            
11             $VERSION = '0.12';
12            
13             # Not sure how useful these are anymore -
14             # may get rid of them soon.
15             use constant PROCESSOR_ARCHITECTURE_INTEL => 0;
16             use constant PROCESSOR_ARCHITECTURE_MIPS => 1;
17             use constant PROCESSOR_ARCHITECTURE_ALPHA => 2;
18             use constant PROCESSOR_ARCHITECTURE_PPC => 3;
19             use constant PROCESSOR_ARCHITECTURE_AMD64 => 9;
20             use constant PROCESSOR_ARCHITECTURE_UNKNOWN => 0xFFFF;
21            
22             my %Procedures = ();
23             my %Types = ();
24             my %Structs = ();
25            
26             #===========================
27             my $check_OS = sub () # Attempt to make this as private as possible
28             {
29             my $dwPlatformId;
30             my $osType;
31            
32             if ( !defined( $Types{'OSVERSIONINFO'} ) ) {
33             # (See GetVersionEx on MSDN)
34             Win32::API::Struct->typedef(
35             OSVERSIONINFO => qw{
36             DWORD dwOSVersionInfoSize;
37             DWORD dwMajorVersion;
38             DWORD dwMinorVersion;
39             DWORD dwBuildNumber;
40             DWORD dwPlatformID;
41             TCHAR szCSDVersion[128];
42             }
43             );
44             $Types{'OSVERSIONINFO'} = 1;
45             }
46            
47             if ( !defined( $Procedures{'GetVersionEx'} ) ) {
48             Win32::API->Import( 'kernel32',
49             'BOOL GetVersionEx(LPOSVERSIONINFO lpOSVersionInfo)' )
50             or die
51             "Could not locate kernel32.dll - SystemInfo.pm cannot continue\n";
52             $Procedures{'GetVersionEx'} = 1;
53             }
54            
55             my $OSVERSIONINFO;
56             if ( !defined( $Structs{'OSVERSIONINFO'} ) ) {
57             $OSVERSIONINFO = Win32::API::Struct->new('OSVERSIONINFO');
58             $Structs{'OSVERSIONINFO'} = $OSVERSIONINFO;
59             }
60             else {
61             $OSVERSIONINFO = $Structs{'OSVERSIONINFO'};
62             }
63            
64             {
65             # Ignore Win32::API warnings. It's ugly, but what are you gonna do?
66             local $SIG{__WARN__} = sub { };
67             $OSVERSIONINFO->{'dwMajorVersion'} = 0;
68             $OSVERSIONINFO->{'dwMinorVersion'} = 0;
69             $OSVERSIONINFO->{'dwBuildNumber'} = 0;
70             $OSVERSIONINFO->{'dwPlatformID'} = 0;
71             $OSVERSIONINFO->{'szCSDVersion'} = "" x 128;
72             $OSVERSIONINFO->{'dwOSVersionInfoSize'} =
73             $OSVERSIONINFO->sizeof();
74            
75             GetVersionEx($OSVERSIONINFO) or return undef;
76            
77             $dwPlatformId = $OSVERSIONINFO->{dwPlatformID};
78             if ( $dwPlatformId == 2 ) {
79             my $majorVersion = $OSVERSIONINFO->{dwMajorVersion};
80             if ( $majorVersion == 4 ) {
81             $osType = "WinNT";
82             }
83             else {
84             $osType = "Win2K";
85             }
86             }
87             elsif ( $dwPlatformId == 1 ) { $osType = "Win9x"; }
88            
89             return ( $osType ne "" ) ? $osType : undef;
90             }
91             };
92             #==================
93            
94             #==================
95             my $canUse64Bit = sub () { # Another private sub - see if we can do 64 bit
96             eval { my $foo = pack( "Q", 1234 ) };
97             return ($@) ? 0 : 1;
98             };
99             #==================
100            
101             #==================
102             sub MemoryStatus (\%;$) {
103             my $return = shift; #hash to return
104             my $ret_type ||= shift || "B"; #what format does the user want?
105             my %fmt_types =
106             ( B => 1, KB => 1024, MB => 1024 * 1024, GB => 1024 * 1024 * 1024 );
107             my @params = qw(MemLoad TotalPhys AvailPhys TotalPage
108             AvailPage TotalVirtual AvailVirtual);
109             my %results; #results of fn call
110             my $MemFormat; #divisor for format
111             my $dwMSLength; #validator from fn call
112            
113             $MemFormat =
114             ( $ret_type =~ /^[BKMG]B?$/ ) ? $fmt_types{$ret_type} : $fmt_types{B};
115            
116             # Determine operating system
117             return undef unless my $OS = &$check_OS;
118            
119             my $use64Bit = &$canUse64Bit;
120            
121             if ( ( $OS eq "Win2K" ) && ($use64Bit) ) {
122             if ( !defined( $Types{'MEMORYSTATUSEX'} ) ) {
123            
124             # (See GlobalMemoryStatusEx on MSDN)
125             Win32::API::Struct->typedef(
126             MEMORYSTATUSEX => qw{
127             DWORD dwLength;
128             DWORD MemLoad;
129             ULONGLONG TotalPhys;
130             ULONGLONG AvailPhys;
131             ULONGLONG TotalPage;
132             ULONGLONG AvailPage;
133             ULONGLONG TotalVirtual;
134             ULONGLONG AvailVirtual;
135             ULONGLONG AvailExtendedVirtual;
136             }
137             );
138             $Types{'MEMORYSTATUSEX'} = 1;
139             }
140            
141             if ( !defined( $Procedures{'GlobalMemoryStatusEx'} ) ) {
142             Win32::API->Import( 'kernel32',
143             'BOOL GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpMemoryStatusEx)' )
144             or die
145             "Could not locate kernel32.dll - SystemInfo.pm cannot continue\n";
146             $Procedures{'GlobalMemoryStatusEx'} = 1;
147             }
148            
149             my $MEMORYSTATUSEX;
150             if ( !defined( $Structs{'MEMORYSTATUSEX'} ) ) {
151             $MEMORYSTATUSEX = Win32::API::Struct->new('MEMORYSTATUSEX');
152             }
153             else {
154             $MEMORYSTATUSEX = $Structs{'MEMORYSTATUSEX'};
155             }
156             $MEMORYSTATUSEX->{dwLength} = $MEMORYSTATUSEX->sizeof();
157             $MEMORYSTATUSEX->{MemLoad} = 0;
158             $MEMORYSTATUSEX->{TotalPhys} = 0;
159             $MEMORYSTATUSEX->{AvailPhys} = 0;
160             $MEMORYSTATUSEX->{TotalPage} = 0;
161             $MEMORYSTATUSEX->{AvailPage} = 0;
162             $MEMORYSTATUSEX->{TotalVirtual} = 0;
163             $MEMORYSTATUSEX->{AvailVirtual} = 0;
164             $MEMORYSTATUSEX->{AvailExtendedVirtual} = 0;
165            
166             GlobalMemoryStatusEx($MEMORYSTATUSEX);
167            
168             if ( keys(%$return) == 0 ) {
169             foreach (@params) {
170             $return->{$_} =
171             ( $_ eq "MemLoad" )
172             ? $MEMORYSTATUSEX->{$_}
173             : $MEMORYSTATUSEX->{$_} / $MemFormat;
174             }
175             }
176             else {
177             foreach (@params) {
178             $return->{$_} = $MEMORYSTATUSEX->{$_} / $MemFormat
179             unless ( !defined( $return->{$_} ) );
180             }
181             }
182             }
183             else {
184            
185             if ( !defined( $Types{'MEMORYSTATUS'} ) ) {
186            
187             # (See GlobalMemoryStatus on MSDN)
188             # I had to change some of the types to get the struct to
189             # play nicely with Win32::API. The SIZE_T's are actually
190             # DWORDS in previous versions of the Win32 API, so this
191             # change doesn't hurt anything.
192             # The names of the members in the struct are different than
193             # in the API to make my life easier, and to keep the same
194             # return values this method has always had.
195             Win32::API::Struct->typedef(
196             MEMORYSTATUS => qw{
197             DWORD dwLength;
198             DWORD MemLoad;
199             DWORD TotalPhys;
200             DWORD AvailPhys;
201             DWORD TotalPage;
202             DWORD AvailPage;
203             DWORD TotalVirtual;
204             DWORD AvailVirtual;
205             }
206             );
207             $Types{'MEMORYSTATUS'} = 1;
208             }
209            
210             if ( !defined( $Procedures{'GlobalMemoryStatus'} ) ) {
211             Win32::API->Import( 'kernel32',
212             'VOID GlobalMemoryStatus(LPMEMORYSTATUS lpMemoryStatus)' )
213             or die
214             "Could not locate kernel32.dll - SystemInfo.pm cannot continue\n";
215             $Procedures{'GlobalMemoryStatus'} = 1;
216             }
217            
218             my $MEMORYSTATUS;
219             if ( !defined( $Structs{'MEMORYSTATUS'} ) ) {
220             $MEMORYSTATUS = Win32::API::Struct->new('MEMORYSTATUS');
221             $Structs{'MEMORYSTATUS'} = $MEMORYSTATUS;
222             }
223             else {
224             $MEMORYSTATUS = $Structs{'MEMORYSTATUS'};
225             }
226             $MEMORYSTATUS->align('auto');
227             $MEMORYSTATUS->{'dwLength'} = 0;
228             $MEMORYSTATUS->{'MemLoad'} = 0;
229             $MEMORYSTATUS->{'TotalPhys'} = 0;
230             $MEMORYSTATUS->{'AvailPhys'} = 0;
231             $MEMORYSTATUS->{'TotalPage'} = 0;
232             $MEMORYSTATUS->{'AvailPage'} = 0;
233             $MEMORYSTATUS->{'TotalVirtual'} = 0;
234             $MEMORYSTATUS->{'AvailVirtual'} = 0;
235            
236             GlobalMemoryStatus($MEMORYSTATUS);
237             return undef if $MEMORYSTATUS->{dwLength} == 0;
238            
239             if ( keys(%$return) == 0 ) {
240             foreach (@params) {
241             $return->{$_} =
242             ( $_ eq "MemLoad" )
243             ? $MEMORYSTATUS->{$_}
244             : $MEMORYSTATUS->{$_} / $MemFormat;
245             }
246             }
247             else {
248             foreach (@params) {
249             $return->{$_} = $MEMORYSTATUS->{$_} / $MemFormat
250             unless ( !defined( $return->{$_} ) );
251             }
252             }
253             }
254             1;
255             }
256             #==========================
257            
258             #==========================
259             sub ProcessorInfo (;\%) {
260             my $allHash = shift;
261            
262             # Determine operating system
263             return undef unless my $OS = &$check_OS;
264            
265             if ( !defined( $Types{'SYSTEM_INFO'} ) ) {
266            
267             # (See GetSystemInfo on MSDN)
268             Win32::API::Struct->typedef(
269             SYSTEM_INFO => qw{
270             WORD wProcessorArchitecture;
271             WORD wReserved;
272             DWORD dwPageSize;
273             UINT_PTR lpMinimumApplicationAddress;
274             UINT_PTR lpMaximumApplicationAddress;
275             DWORD_PTR dwActiveProcessorMask;
276             DWORD dwNumberOfProcessors;
277             DWORD dwProcessorType;
278             DWORD dwAllocationGranularity;
279             WORD wProcessorLevel;
280             WORD wProcessorRevision;
281             }
282             );
283             $Types{'SYSTEM_INFO'} = 1;
284             }
285            
286             if ( !defined( $Procedures{'GetSystemInfo'} ) ) {
287             Win32::API->Import( 'kernel32',
288             'VOID GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)' )
289             or die
290             "Could not locate kernel32.dll - SystemInfo.pm cannot continue\n";
291             $Procedures{'GetSystemInfo'} = 1;
292             }
293             my $SYSTEM_INFO;
294             if ( !defined( $Structs{'SYSTEM_INFO'} ) ) {
295             $SYSTEM_INFO = Win32::API::Struct->new('SYSTEM_INFO');
296             $Structs{'SYSTEM_INFO'} = $SYSTEM_INFO;
297             }
298             else {
299             $SYSTEM_INFO = $Structs{'SYSTEM_INFO'};
300             }
301            
302             {
303             # Ignore Win32::API warnings. It's ugly, but what are you gonna do?
304             local $SIG{__WARN__} = sub { };
305             $SYSTEM_INFO->{'wProcessorArchitecture'} = 0;
306             $SYSTEM_INFO->{'wReserved'} = 0;
307             $SYSTEM_INFO->{'dwPageSize'} = 0;
308             $SYSTEM_INFO->{'lpMinimumApplicationAddress'} = 0;
309             $SYSTEM_INFO->{'lpMaximumApplicationAddress'} = 0;
310             $SYSTEM_INFO->{'dwActiveProcessorMask'} = 0;
311             $SYSTEM_INFO->{'dwNumberOfProcessors'} = 0;
312             $SYSTEM_INFO->{'dwProcessorType'} = 0;
313             $SYSTEM_INFO->{'dwAllocationGranularity'} = 0;
314             $SYSTEM_INFO->{'wProcessorLevel'} = 0;
315             $SYSTEM_INFO->{'wProcessorRevision'} = 0;
316             GetSystemInfo($SYSTEM_INFO);
317            
318             my $proc_type; # Holds 386,586,PPC, etc
319             my $num_proc; # number of processors
320            
321             $num_proc = $SYSTEM_INFO->{dwNumberOfProcessors};
322             if ( $OS eq "Win9x" ) {
323             $proc_type = $SYSTEM_INFO->{dwProcessorType};
324             }
325             elsif ( ( $OS eq "WinNT" ) || ( $OS eq "Win2K" ) ) {
326             my $proc_level; # first digit of Intel chip (5,6,etc)
327             my $proc_val;
328             $proc_val = $SYSTEM_INFO->{wProcessorArchitecture};
329             $proc_level = $SYSTEM_INFO->{wProcessorLevel};
330            
331             # $proc_type is the return value of ProcessorInfo
332             if ( $proc_val == PROCESSOR_ARCHITECTURE_INTEL ) {
333             $proc_type = $proc_level . "86";
334             }
335             elsif ( $proc_val == PROCESSOR_ARCHITECTURE_AMD64 ) {
336             $proc_type = "x64";
337             }
338             elsif ( $proc_val == PROCESSOR_ARCHITECTURE_MIPS ) {
339             $proc_type = "MIPS";
340             }
341             elsif ( $proc_val == PROCESSOR_ARCHITECTURE_PPC ) {
342             $proc_type = "PPC";
343             }
344             elsif ( $proc_val == PROCESSOR_ARCHITECTURE_ALPHA ) {
345             $proc_type = "ALPHA";
346             }
347             else { $proc_type = "UNKNOWN"; }
348             }
349            
350             # if a hash was supplied, fill it with all info
351             if ( defined($allHash) ) {
352             $allHash->{NumProcessors} = $num_proc;
353             $Registry->Delimiter("/");
354             for ( my $i = 0 ; $i < $num_proc ; $i++ ) {
355             my $procinfo = $Registry->Open(
356             "LMachine/Hardware/Description/System/CentralProcessor/$i",
357             { Access => KEY_READ() }
358             );
359             my %prochash;
360             $prochash{Identifier} = $procinfo->{Identifier};
361             $prochash{VendorIdentifier} =
362             $procinfo->{VendorIdentifier};
363             if ( $OS eq "Win9x" ) {
364             $prochash{MHZ} = -1;
365             }
366             else {
367             $prochash{MHZ} = hex $procinfo->{"~MHz"};
368             }
369             $prochash{ProcessorName} =
370             $procinfo->{ProcessorNameString};
371             $allHash->{"Processor$i"} = \%prochash;
372             }
373             }
374             return $proc_type;
375             }
376             }
377            
378             1;
379             __END__