Skip to content

Commit

Permalink
"Improve platform module: use rtlGetVersion to determine win version …
Browse files Browse the repository at this point in the history
…before trying to create a process using cmd.exe ver"
  • Loading branch information
tomergert committed Jan 25, 2025
1 parent d40692d commit 0050f39
Showing 1 changed file with 70 additions and 28 deletions.
98 changes: 70 additions & 28 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
"""

__version__ = '1.0.9'
__version__ = '1.0.10'

import collections
import os
Expand Down Expand Up @@ -384,6 +384,49 @@ def win32_edition():

return None

def _format_sp_and_product_type(spmajor, spminor, product_type):
csd = f"SP{spmajor}.{spminor}" if spminor else f"SP{spmajor}"
is_client = (int(product_type) == 1)
return csd, is_client

def _get_version_using_rtlgetversion():
import ctypes
class OSVERSIONINFOEXW(ctypes.Structure):
_fields_ = [
("dwOSVersionInfoSize", ctypes.c_uint32),
("dwMajorVersion", ctypes.c_uint32),
("dwMinorVersion", ctypes.c_uint32),
("dwBuildNumber", ctypes.c_uint32),
("dwPlatformId", ctypes.c_uint32),
("szCSDVersion", ctypes.c_wchar * 128), # Service Pack name
("wServicePackMajor", ctypes.c_uint16), # Major Service Pack version
("wServicePackMinor", ctypes.c_uint16), # Minor Service Pack version
("wSuiteMask", ctypes.c_uint16),
("wProductType", ctypes.c_uint8), # Type of product (Workstation, etc.)
("wReserved", ctypes.c_uint8) # Reserved
]

# Initialize OSVERSIONINFOEXW structure
os_version = OSVERSIONINFOEXW()
os_version.dwOSVersionInfoSize = ctypes.sizeof(OSVERSIONINFOEXW)

# Load ntdll.dll and call RtlGetVersion
ntdll = ctypes.WinDLL("ntdll")
rtl_get_version = ntdll.RtlGetVersion
rtl_get_version(ctypes.byref(os_version))

# Extract the version details
major = os_version.dwMajorVersion
minor = os_version.dwMinorVersion
build = os_version.dwBuildNumber
spmajor = os_version.wServicePackMajor
spminor = os_version.wServicePackMinor
product_type = os_version.wProductType

version = f"{major}.{minor}.{build}"
csd, is_client = _format_sp_and_product_type(spmajor, spminor, product_type)
return version, csd, is_client

def _win32_ver(version, csd, ptype):
# Try using WMI first, as this is the canonical source of data
try:
Expand All @@ -395,40 +438,39 @@ def _win32_ver(version, csd, ptype):
'ServicePackMajorVersion',
'ServicePackMinorVersion',
)
is_client = (int(product_type) == 1)
if spminor and spminor != '0':
csd = f'SP{spmajor}.{spminor}'
else:
csd = f'SP{spmajor}'
csd, is_client = _format_sp_and_product_type(spmajor, spminor, product_type)
return version, csd, ptype, is_client
except OSError:
pass

# Fall back to a combination of sys.getwindowsversion and "ver"
try:
from sys import getwindowsversion
except ImportError:
return version, csd, ptype, True

winver = getwindowsversion()
is_client = (getattr(winver, 'product_type', 1) == 1)
# Fall back to RtlGetVersion using ntdll
try:
version = _syscmd_ver()[2]
major, minor, build = map(int, version.split('.'))
except ValueError:
major, minor, build = winver.platform_version or winver[:3]
version = '{0}.{1}.{2}'.format(major, minor, build)

# getwindowsversion() reflect the compatibility mode Python is
# running under, and so the service pack value is only going to be
# valid if the versions match.
if winver[:2] == (major, minor):
version, csd, is_client = _get_version_using_rtlgetversion()
except Exception:
# Fall back to a combination of sys.getwindowsversion and "ver"
try:
csd = 'SP{}'.format(winver.service_pack_major)
except AttributeError:
if csd[:13] == 'Service Pack ':
csd = 'SP' + csd[13:]
from sys import getwindowsversion
except ImportError:
return version, csd, ptype, True

winver = getwindowsversion()
is_client = (getattr(winver, 'product_type', 1) == 1)
try:
version = _syscmd_ver()[2]
major, minor, build = map(int, version.split('.'))
except ValueError:
major, minor, build = winver.platform_version or winver[:3]
version = '{0}.{1}.{2}'.format(major, minor, build)

# getwindowsversion() reflect the compatibility mode Python is
# running under, and so the service pack value is only going to be
# valid if the versions match.
if winver[:2] == (major, minor):
try:
csd = 'SP{}'.format(winver.service_pack_major)
except AttributeError:
if csd[:13] == 'Service Pack ':
csd = 'SP' + csd[13:]
try:
import winreg
except ImportError:
Expand Down

0 comments on commit 0050f39

Please sign in to comment.