|
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