26
26
# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27
27
# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28
28
# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
29
- # Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
29
+ # Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
30
+ # Dower
30
31
#
31
32
# History:
32
33
#
33
34
# <see CVS and SVN checkin messages for history>
34
35
#
36
+ # 1.0.8 - changed Windows support to read version from kernel32.dll
35
37
# 1.0.7 - added DEV_NULL
36
38
# 1.0.6 - added linux_distribution()
37
39
# 1.0.5 - fixed Java support to allow running the module on Jython
@@ -469,189 +471,139 @@ def _syscmd_ver(system='', release='', version='',
469
471
version = _norm_version (version )
470
472
return system , release , version
471
473
472
- def _win32_getvalue (key , name , default = '' ):
474
+ _WIN32_CLIENT_RELEASES = {
475
+ (5 , 0 ): "2000" ,
476
+ (5 , 1 ): "XP" ,
477
+ # Strictly, 5.2 client is XP 64-bit, but platform.py historically
478
+ # has always called it 2003 Server
479
+ (5 , 2 ): "2003Server" ,
480
+ (5 , None ): "post2003" ,
481
+
482
+ (6 , 0 ): "Vista" ,
483
+ (6 , 1 ): "7" ,
484
+ (6 , 2 ): "8" ,
485
+ (6 , 3 ): "8.1" ,
486
+ (6 , None ): "post8.1" ,
487
+
488
+ (10 , 0 ): "10" ,
489
+ (10 , None ): "post10" ,
490
+ }
473
491
474
- """ Read a value for name from the registry key.
492
+ # Server release name lookup will default to client names if necessary
493
+ _WIN32_SERVER_RELEASES = {
494
+ (5 , 2 ): "2003Server" ,
475
495
476
- In case this fails, default is returned.
496
+ (6 , 0 ): "2008Server" ,
497
+ (6 , 1 ): "2008ServerR2" ,
498
+ (6 , 2 ): "2012Server" ,
499
+ (6 , 3 ): "2012ServerR2" ,
500
+ (6 , None ): "post2012ServerR2" ,
501
+ }
477
502
478
- """
479
- try :
480
- # Use win32api if available
481
- from win32api import RegQueryValueEx
482
- except ImportError :
483
- # On Python 2.0 and later, emulate using winreg
484
- import winreg
485
- RegQueryValueEx = winreg .QueryValueEx
486
- try :
487
- return RegQueryValueEx (key , name )
488
- except :
489
- return default
503
+ def _get_real_winver (maj , min , build ):
504
+ if maj < 6 or (maj == 6 and min < 2 ):
505
+ return maj , min , build
506
+
507
+ from ctypes import (c_buffer , POINTER , byref , create_unicode_buffer ,
508
+ Structure , WinDLL )
509
+ from ctypes .wintypes import DWORD , HANDLE
510
+
511
+ class VS_FIXEDFILEINFO (Structure ):
512
+ _fields_ = [
513
+ ("dwSignature" , DWORD ),
514
+ ("dwStrucVersion" , DWORD ),
515
+ ("dwFileVersionMS" , DWORD ),
516
+ ("dwFileVersionLS" , DWORD ),
517
+ ("dwProductVersionMS" , DWORD ),
518
+ ("dwProductVersionLS" , DWORD ),
519
+ ("dwFileFlagsMask" , DWORD ),
520
+ ("dwFileFlags" , DWORD ),
521
+ ("dwFileOS" , DWORD ),
522
+ ("dwFileType" , DWORD ),
523
+ ("dwFileSubtype" , DWORD ),
524
+ ("dwFileDateMS" , DWORD ),
525
+ ("dwFileDateLS" , DWORD ),
526
+ ]
527
+
528
+ kernel32 = WinDLL ('kernel32' )
529
+ version = WinDLL ('version' )
530
+
531
+ # We will immediately double the length up to MAX_PATH, but the
532
+ # path may be longer, so we retry until the returned string is
533
+ # shorter than our buffer.
534
+ name_len = actual_len = 130
535
+ while actual_len == name_len :
536
+ name_len *= 2
537
+ name = create_unicode_buffer (name_len )
538
+ actual_len = kernel32 .GetModuleFileNameW (HANDLE (kernel32 ._handle ),
539
+ name , len (name ))
540
+ if not actual_len :
541
+ return maj , min , build
542
+
543
+ size = version .GetFileVersionInfoSizeW (name , None )
544
+ if not size :
545
+ return maj , min , build
546
+
547
+ ver_block = c_buffer (size )
548
+ if (not version .GetFileVersionInfoW (name , None , size , ver_block ) or
549
+ not ver_block ):
550
+ return maj , min , build
551
+
552
+ pvi = POINTER (VS_FIXEDFILEINFO )()
553
+ if not version .VerQueryValueW (ver_block , "" , byref (pvi ), byref (DWORD ())):
554
+ return maj , min , build
555
+
556
+ maj = pvi .contents .dwProductVersionMS >> 16
557
+ min = pvi .contents .dwProductVersionMS & 0xFFFF
558
+ build = pvi .contents .dwProductVersionLS >> 16
559
+
560
+ return maj , min , build
490
561
491
562
def win32_ver (release = '' , version = '' , csd = '' , ptype = '' ):
563
+ from sys import getwindowsversion
564
+ try :
565
+ from winreg import OpenKeyEx , QueryValueEx , CloseKey , HKEY_LOCAL_MACHINE
566
+ except ImportError :
567
+ from _winreg import OpenKeyEx , QueryValueEx , CloseKey , HKEY_LOCAL_MACHINE
492
568
493
- """ Get additional version information from the Windows Registry
494
- and return a tuple (version, csd, ptype) referring to version
495
- number, CSD level (service pack), and OS type (multi/single
496
- processor).
497
-
498
- As a hint: ptype returns 'Uniprocessor Free' on single
499
- processor NT machines and 'Multiprocessor Free' on multi
500
- processor machines. The 'Free' refers to the OS version being
501
- free of debugging code. It could also state 'Checked' which
502
- means the OS version uses debugging code, i.e. code that
503
- checks arguments, ranges, etc. (Thomas Heller).
569
+ winver = getwindowsversion ()
570
+ maj , min , build = _get_real_winver (* winver [:3 ])
571
+ version = '{0}.{1}.{2}' .format (maj , min , build )
504
572
505
- Note: this function works best with Mark Hammond's win32
506
- package installed, but also on Python 2.3 and later. It
507
- obviously only runs on Win32 compatible platforms.
573
+ release = ( _WIN32_CLIENT_RELEASES . get (( maj , min )) or
574
+ _WIN32_CLIENT_RELEASES . get (( maj , None )) or
575
+ release )
508
576
509
- """
510
- # XXX Is there any way to find out the processor type on WinXX ?
511
- # XXX Is win32 available on Windows CE ?
512
- #
513
- # Adapted from code posted by Karl Putland to comp.lang.python.
514
- #
515
- # The mappings between reg. values and release names can be found
516
- # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
517
-
518
- # Import the needed APIs
519
- try :
520
- from win32api import RegQueryValueEx , RegOpenKeyEx , \
521
- RegCloseKey , GetVersionEx
522
- from win32con import HKEY_LOCAL_MACHINE , VER_PLATFORM_WIN32_NT , \
523
- VER_PLATFORM_WIN32_WINDOWS , VER_NT_WORKSTATION
524
- except ImportError :
525
- # Emulate the win32api module using Python APIs
577
+ # getwindowsversion() reflect the compatibility mode Python is
578
+ # running under, and so the service pack value is only going to be
579
+ # valid if the versions match.
580
+ if winver [:2 ] == (maj , min ):
526
581
try :
527
- sys . getwindowsversion
582
+ csd = 'SP{}' . format ( winver . service_pack_major )
528
583
except AttributeError :
529
- # No emulation possible, so return the defaults...
530
- return release , version , csd , ptype
531
- else :
532
- # Emulation using winreg (added in Python 2.0) and
533
- # sys.getwindowsversion() (added in Python 2.3)
534
- import winreg
535
- GetVersionEx = sys .getwindowsversion
536
- RegQueryValueEx = winreg .QueryValueEx
537
- RegOpenKeyEx = winreg .OpenKeyEx
538
- RegCloseKey = winreg .CloseKey
539
- HKEY_LOCAL_MACHINE = winreg .HKEY_LOCAL_MACHINE
540
- VER_PLATFORM_WIN32_WINDOWS = 1
541
- VER_PLATFORM_WIN32_NT = 2
542
- VER_NT_WORKSTATION = 1
543
- VER_NT_SERVER = 3
544
- REG_SZ = 1
545
-
546
- # Find out the registry key and some general version infos
547
- winver = GetVersionEx ()
548
- maj , min , buildno , plat , csd = winver
549
- version = '%i.%i.%i' % (maj , min , buildno & 0xFFFF )
550
- if hasattr (winver , "service_pack" ):
551
- if winver .service_pack != "" :
552
- csd = 'SP%s' % winver .service_pack_major
553
- else :
554
- if csd [:13 ] == 'Service Pack ' :
555
- csd = 'SP' + csd [13 :]
556
-
557
- if plat == VER_PLATFORM_WIN32_WINDOWS :
558
- regkey = 'SOFTWARE\\ Microsoft\\ Windows\\ CurrentVersion'
559
- # Try to guess the release name
560
- if maj == 4 :
561
- if min == 0 :
562
- release = '95'
563
- elif min == 10 :
564
- release = '98'
565
- elif min == 90 :
566
- release = 'Me'
567
- else :
568
- release = 'postMe'
569
- elif maj == 5 :
570
- release = '2000'
571
-
572
- elif plat == VER_PLATFORM_WIN32_NT :
573
- regkey = 'SOFTWARE\\ Microsoft\\ Windows NT\\ CurrentVersion'
574
- if maj <= 4 :
575
- release = 'NT'
576
- elif maj == 5 :
577
- if min == 0 :
578
- release = '2000'
579
- elif min == 1 :
580
- release = 'XP'
581
- elif min == 2 :
582
- release = '2003Server'
583
- else :
584
- release = 'post2003'
585
- elif maj == 6 :
586
- if hasattr (winver , "product_type" ):
587
- product_type = winver .product_type
588
- else :
589
- product_type = VER_NT_WORKSTATION
590
- # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
591
- # or help from the registry, we cannot properly identify
592
- # non-workstation versions.
593
- try :
594
- key = RegOpenKeyEx (HKEY_LOCAL_MACHINE , regkey )
595
- name , type = RegQueryValueEx (key , "ProductName" )
596
- # Discard any type that isn't REG_SZ
597
- if type == REG_SZ and name .find ("Server" ) != - 1 :
598
- product_type = VER_NT_SERVER
599
- except OSError :
600
- # Use default of VER_NT_WORKSTATION
601
- pass
602
-
603
- if min == 0 :
604
- if product_type == VER_NT_WORKSTATION :
605
- release = 'Vista'
606
- else :
607
- release = '2008Server'
608
- elif min == 1 :
609
- if product_type == VER_NT_WORKSTATION :
610
- release = '7'
611
- else :
612
- release = '2008ServerR2'
613
- elif min == 2 :
614
- if product_type == VER_NT_WORKSTATION :
615
- release = '8'
616
- else :
617
- release = '2012Server'
618
- else :
619
- release = 'post2012Server'
584
+ if csd [:13 ] == 'Service Pack ' :
585
+ csd = 'SP' + csd [13 :]
620
586
621
- else :
622
- if not release :
623
- # E.g. Win3.1 with win32s
624
- release = '%i.%i' % ( maj , min )
625
- return release , version , csd , ptype
587
+ # VER_NT_SERVER = 3
588
+ if getattr ( winver , 'product_type' , None ) == 3 :
589
+ release = ( _WIN32_SERVER_RELEASES . get (( maj , min )) or
590
+ _WIN32_SERVER_RELEASES . get (( maj , None )) or
591
+ release )
626
592
627
- # Open the registry key
593
+ key = None
628
594
try :
629
- keyCurVer = RegOpenKeyEx (HKEY_LOCAL_MACHINE , regkey )
630
- # Get a value to make sure the key exists...
631
- RegQueryValueEx ( keyCurVer , 'SystemRoot' )
595
+ key = OpenKeyEx (HKEY_LOCAL_MACHINE ,
596
+ r'SOFTWARE\Microsoft\Windows NT\CurrentVersion' )
597
+ ptype = QueryValueEx ( key , 'CurrentType' )[ 0 ]
632
598
except :
633
- return release , version , csd , ptype
634
-
635
- # Parse values
636
- #subversion = _win32_getvalue(keyCurVer,
637
- # 'SubVersionNumber',
638
- # ('',1))[0]
639
- #if subversion:
640
- # release = release + subversion # 95a, 95b, etc.
641
- build = _win32_getvalue (keyCurVer ,
642
- 'CurrentBuildNumber' ,
643
- ('' , 1 ))[0 ]
644
- ptype = _win32_getvalue (keyCurVer ,
645
- 'CurrentType' ,
646
- (ptype , 1 ))[0 ]
647
-
648
- # Normalize version
649
- version = _norm_version (version , build )
650
-
651
- # Close key
652
- RegCloseKey (keyCurVer )
599
+ pass
600
+ finally :
601
+ if key :
602
+ CloseKey (key )
603
+
653
604
return release , version , csd , ptype
654
605
606
+
655
607
def _mac_ver_xml ():
656
608
fn = '/System/Library/CoreServices/SystemVersion.plist'
657
609
if not os .path .exists (fn ):
0 commit comments