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