Skip to content

Commit a23a7a4

Browse files
committed
gh-152433: Windows: improve sys.getwindowsversion(), use RtlGetVersion() and allow build for UWP
1 parent bc08413 commit a23a7a4

2 files changed

Lines changed: 29 additions & 33 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve :func:`sys.getwindowsversion`, use RtlGetVersion() and allow build
2+
for Universal Windows Platform.

Python/sysmodule.c

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,50 +1645,40 @@ static PyStructSequence_Desc windows_version_desc = {
16451645
via indexing, the rest are name only */
16461646
};
16471647

1648-
static PyObject *
1649-
_sys_getwindowsversion_from_kernel32(void)
1648+
static PyObject*
1649+
_sys_getwindowsversion_from_RtlGetVersion(void)
16501650
{
1651-
#ifndef MS_WINDOWS_DESKTOP
1652-
PyErr_SetString(PyExc_OSError, "cannot read version info on this platform");
1653-
return NULL;
1654-
#else
1655-
HANDLE hKernel32;
1656-
wchar_t kernel32_path[MAX_PATH];
1657-
LPVOID verblock;
1658-
DWORD verblock_size;
1659-
VS_FIXEDFILEINFO *ffi;
1660-
UINT ffi_len;
1661-
DWORD realMajor, realMinor, realBuild;
1651+
HMODULE hMod;
1652+
typedef LONG NTSTATUS, * PNTSTATUS;
1653+
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
1654+
RtlGetVersionPtr RtlGetVer;
1655+
1656+
RTL_OSVERSIONINFOW osVerInfo;
1657+
ZeroMemory(&osVerInfo, sizeof(osVerInfo));
1658+
osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
16621659

16631660
Py_BEGIN_ALLOW_THREADS
1664-
hKernel32 = GetModuleHandleW(L"kernel32.dll");
1661+
hMod = GetModuleHandleW(L"ntdll.dll");
16651662
Py_END_ALLOW_THREADS
1666-
if (!hKernel32 || !GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH)) {
1663+
if (!hMod) {
16671664
PyErr_SetFromWindowsErr(0);
16681665
return NULL;
16691666
}
1670-
verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL);
1671-
if (!verblock_size) {
1667+
1668+
Py_BEGIN_ALLOW_THREADS
1669+
RtlGetVer = (RtlGetVersionPtr)GetProcAddress(hMod, "RtlGetVersion");
1670+
Py_END_ALLOW_THREADS
1671+
if (!RtlGetVer) {
16721672
PyErr_SetFromWindowsErr(0);
16731673
return NULL;
16741674
}
1675-
verblock = PyMem_RawMalloc(verblock_size);
1676-
if (!verblock ||
1677-
!GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) ||
1678-
!VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) {
1675+
1676+
if (0 != RtlGetVer(&osVerInfo)) {
16791677
PyErr_SetFromWindowsErr(0);
1680-
if (verblock) {
1681-
PyMem_RawFree(verblock);
1682-
}
16831678
return NULL;
16841679
}
16851680

1686-
realMajor = HIWORD(ffi->dwProductVersionMS);
1687-
realMinor = LOWORD(ffi->dwProductVersionMS);
1688-
realBuild = HIWORD(ffi->dwProductVersionLS);
1689-
PyMem_RawFree(verblock);
1690-
return Py_BuildValue("(kkk)", realMajor, realMinor, realBuild);
1691-
#endif /* !MS_WINDOWS_DESKTOP */
1681+
return Py_BuildValue("(kkk)", osVerInfo.dwMajorVersion, osVerInfo.dwMinorVersion, osVerInfo.dwBuildNumber);
16921682
}
16931683

16941684
/* Disable deprecation warnings about GetVersionEx as the result is
@@ -1719,7 +1709,6 @@ sys_getwindowsversion_impl(PyObject *module)
17191709
{
17201710
PyObject *version;
17211711
int pos = 0;
1722-
OSVERSIONINFOEXW ver;
17231712

17241713
if (PyObject_GetOptionalAttrString(module, "_cached_windows_version", &version) < 0) {
17251714
return NULL;
@@ -1729,6 +1718,8 @@ sys_getwindowsversion_impl(PyObject *module)
17291718
}
17301719
Py_XDECREF(version);
17311720

1721+
OSVERSIONINFOEXW ver;
1722+
ZeroMemory(&ver, sizeof(ver));
17321723
ver.dwOSVersionInfoSize = sizeof(ver);
17331724
if (!GetVersionExW((OSVERSIONINFOW*) &ver))
17341725
return PyErr_SetFromWindowsErr(0);
@@ -1756,11 +1747,13 @@ sys_getwindowsversion_impl(PyObject *module)
17561747
SET_VERSION_INFO(PyLong_FromLong(ver.wSuiteMask));
17571748
SET_VERSION_INFO(PyLong_FromLong(ver.wProductType));
17581749

1750+
#ifdef MS_WINDOWS_DESKTOP
17591751
// GetVersion will lie if we are running in a compatibility mode.
1760-
// We need to read the version info from a system file resource
1752+
// We need to read the version info from kernel with RtlGetVersion
17611753
// to accurately identify the OS version. If we fail for any reason,
17621754
// just return whatever GetVersion said.
1763-
PyObject *realVersion = _sys_getwindowsversion_from_kernel32();
1755+
// UWP return correct version from GetVersionExW, this is not necessary.
1756+
PyObject *realVersion = _sys_getwindowsversion_from_RtlGetVersion();
17641757
if (!realVersion) {
17651758
if (!PyErr_ExceptionMatches(PyExc_WindowsError)) {
17661759
goto error;
@@ -1775,6 +1768,7 @@ sys_getwindowsversion_impl(PyObject *module)
17751768
}
17761769

17771770
SET_VERSION_INFO(realVersion);
1771+
#endif
17781772

17791773
#undef SET_VERSION_INFO
17801774

0 commit comments

Comments
 (0)