Skip to content

Commit 0050f39

Browse files
committed
"Improve platform module: use rtlGetVersion to determine win version before trying to create a process using cmd.exe ver"
1 parent d40692d commit 0050f39

File tree

1 file changed

+70
-28
lines changed

1 file changed

+70
-28
lines changed

Lib/platform.py

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
111111
"""
112112

113-
__version__ = '1.0.9'
113+
__version__ = '1.0.10'
114114

115115
import collections
116116
import os
@@ -384,6 +384,49 @@ def win32_edition():
384384

385385
return None
386386

387+
def _format_sp_and_product_type(spmajor, spminor, product_type):
388+
csd = f"SP{spmajor}.{spminor}" if spminor else f"SP{spmajor}"
389+
is_client = (int(product_type) == 1)
390+
return csd, is_client
391+
392+
def _get_version_using_rtlgetversion():
393+
import ctypes
394+
class OSVERSIONINFOEXW(ctypes.Structure):
395+
_fields_ = [
396+
("dwOSVersionInfoSize", ctypes.c_uint32),
397+
("dwMajorVersion", ctypes.c_uint32),
398+
("dwMinorVersion", ctypes.c_uint32),
399+
("dwBuildNumber", ctypes.c_uint32),
400+
("dwPlatformId", ctypes.c_uint32),
401+
("szCSDVersion", ctypes.c_wchar * 128), # Service Pack name
402+
("wServicePackMajor", ctypes.c_uint16), # Major Service Pack version
403+
("wServicePackMinor", ctypes.c_uint16), # Minor Service Pack version
404+
("wSuiteMask", ctypes.c_uint16),
405+
("wProductType", ctypes.c_uint8), # Type of product (Workstation, etc.)
406+
("wReserved", ctypes.c_uint8) # Reserved
407+
]
408+
409+
# Initialize OSVERSIONINFOEXW structure
410+
os_version = OSVERSIONINFOEXW()
411+
os_version.dwOSVersionInfoSize = ctypes.sizeof(OSVERSIONINFOEXW)
412+
413+
# Load ntdll.dll and call RtlGetVersion
414+
ntdll = ctypes.WinDLL("ntdll")
415+
rtl_get_version = ntdll.RtlGetVersion
416+
rtl_get_version(ctypes.byref(os_version))
417+
418+
# Extract the version details
419+
major = os_version.dwMajorVersion
420+
minor = os_version.dwMinorVersion
421+
build = os_version.dwBuildNumber
422+
spmajor = os_version.wServicePackMajor
423+
spminor = os_version.wServicePackMinor
424+
product_type = os_version.wProductType
425+
426+
version = f"{major}.{minor}.{build}"
427+
csd, is_client = _format_sp_and_product_type(spmajor, spminor, product_type)
428+
return version, csd, is_client
429+
387430
def _win32_ver(version, csd, ptype):
388431
# Try using WMI first, as this is the canonical source of data
389432
try:
@@ -395,40 +438,39 @@ def _win32_ver(version, csd, ptype):
395438
'ServicePackMajorVersion',
396439
'ServicePackMinorVersion',
397440
)
398-
is_client = (int(product_type) == 1)
399-
if spminor and spminor != '0':
400-
csd = f'SP{spmajor}.{spminor}'
401-
else:
402-
csd = f'SP{spmajor}'
441+
csd, is_client = _format_sp_and_product_type(spmajor, spminor, product_type)
403442
return version, csd, ptype, is_client
404443
except OSError:
405444
pass
406445

407-
# Fall back to a combination of sys.getwindowsversion and "ver"
408-
try:
409-
from sys import getwindowsversion
410-
except ImportError:
411-
return version, csd, ptype, True
412-
413-
winver = getwindowsversion()
414-
is_client = (getattr(winver, 'product_type', 1) == 1)
446+
# Fall back to RtlGetVersion using ntdll
415447
try:
416-
version = _syscmd_ver()[2]
417-
major, minor, build = map(int, version.split('.'))
418-
except ValueError:
419-
major, minor, build = winver.platform_version or winver[:3]
420-
version = '{0}.{1}.{2}'.format(major, minor, build)
421-
422-
# getwindowsversion() reflect the compatibility mode Python is
423-
# running under, and so the service pack value is only going to be
424-
# valid if the versions match.
425-
if winver[:2] == (major, minor):
448+
version, csd, is_client = _get_version_using_rtlgetversion()
449+
except Exception:
450+
# Fall back to a combination of sys.getwindowsversion and "ver"
426451
try:
427-
csd = 'SP{}'.format(winver.service_pack_major)
428-
except AttributeError:
429-
if csd[:13] == 'Service Pack ':
430-
csd = 'SP' + csd[13:]
452+
from sys import getwindowsversion
453+
except ImportError:
454+
return version, csd, ptype, True
431455

456+
winver = getwindowsversion()
457+
is_client = (getattr(winver, 'product_type', 1) == 1)
458+
try:
459+
version = _syscmd_ver()[2]
460+
major, minor, build = map(int, version.split('.'))
461+
except ValueError:
462+
major, minor, build = winver.platform_version or winver[:3]
463+
version = '{0}.{1}.{2}'.format(major, minor, build)
464+
465+
# getwindowsversion() reflect the compatibility mode Python is
466+
# running under, and so the service pack value is only going to be
467+
# valid if the versions match.
468+
if winver[:2] == (major, minor):
469+
try:
470+
csd = 'SP{}'.format(winver.service_pack_major)
471+
except AttributeError:
472+
if csd[:13] == 'Service Pack ':
473+
csd = 'SP' + csd[13:]
432474
try:
433475
import winreg
434476
except ImportError:

0 commit comments

Comments
 (0)