Skip to content

Commit fdb6a9c

Browse files
committed
gh-152433: Windows: improve sys.getwindowsversion() fix return incorrect build number for Windows 11+ and fix errors in UWP
1 parent bc08413 commit fdb6a9c

2 files changed

Lines changed: 22 additions & 6 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`: fix return incorrect build number for
2+
Windows 11+ and fix errors in Universal Windows Platform.

Python/sysmodule.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Data members:
5151
# ifndef WIN32_LEAN_AND_MEAN
5252
# define WIN32_LEAN_AND_MEAN
5353
# endif
54+
# define REG_CURRENT_VERSION L"Software\\Microsoft\\Windows NT\\CurrentVersion"
5455
# include <windows.h>
5556
#endif /* MS_WINDOWS */
5657

@@ -1645,13 +1646,10 @@ static PyStructSequence_Desc windows_version_desc = {
16451646
via indexing, the rest are name only */
16461647
};
16471648

1649+
#ifdef MS_WINDOWS_DESKTOP
16481650
static PyObject *
16491651
_sys_getwindowsversion_from_kernel32(void)
16501652
{
1651-
#ifndef MS_WINDOWS_DESKTOP
1652-
PyErr_SetString(PyExc_OSError, "cannot read version info on this platform");
1653-
return NULL;
1654-
#else
16551653
HANDLE hKernel32;
16561654
wchar_t kernel32_path[MAX_PATH];
16571655
LPVOID verblock;
@@ -1687,9 +1685,21 @@ _sys_getwindowsversion_from_kernel32(void)
16871685
realMinor = LOWORD(ffi->dwProductVersionMS);
16881686
realBuild = HIWORD(ffi->dwProductVersionLS);
16891687
PyMem_RawFree(verblock);
1688+
1689+
// Obtain the build number from Windows registry in case of Windows 10/11
1690+
if (realMajor == 10 && realMinor == 0) {
1691+
wchar_t currentBuild[32] = {0};
1692+
DWORD len = sizeof(currentBuild);
1693+
if (ERROR_SUCCESS == RegGetValueW(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, L"CurrentBuild",
1694+
RRF_RT_REG_SZ, NULL, &currentBuild, &len))
1695+
{
1696+
realBuild = _wtol(currentBuild);
1697+
}
1698+
}
1699+
16901700
return Py_BuildValue("(kkk)", realMajor, realMinor, realBuild);
1691-
#endif /* !MS_WINDOWS_DESKTOP */
16921701
}
1702+
#endif /* MS_WINDOWS_DESKTOP */
16931703

16941704
/* Disable deprecation warnings about GetVersionEx as the result is
16951705
being passed straight through to the caller, who is responsible for
@@ -1719,7 +1729,6 @@ sys_getwindowsversion_impl(PyObject *module)
17191729
{
17201730
PyObject *version;
17211731
int pos = 0;
1722-
OSVERSIONINFOEXW ver;
17231732

17241733
if (PyObject_GetOptionalAttrString(module, "_cached_windows_version", &version) < 0) {
17251734
return NULL;
@@ -1729,6 +1738,8 @@ sys_getwindowsversion_impl(PyObject *module)
17291738
}
17301739
Py_XDECREF(version);
17311740

1741+
OSVERSIONINFOEXW ver;
1742+
ZeroMemory(&ver, sizeof(ver));
17321743
ver.dwOSVersionInfoSize = sizeof(ver);
17331744
if (!GetVersionExW((OSVERSIONINFOW*) &ver))
17341745
return PyErr_SetFromWindowsErr(0);
@@ -1756,10 +1767,12 @@ sys_getwindowsversion_impl(PyObject *module)
17561767
SET_VERSION_INFO(PyLong_FromLong(ver.wSuiteMask));
17571768
SET_VERSION_INFO(PyLong_FromLong(ver.wProductType));
17581769

1770+
#ifdef MS_WINDOWS_DESKTOP
17591771
// GetVersion will lie if we are running in a compatibility mode.
17601772
// We need to read the version info from a system file resource
17611773
// to accurately identify the OS version. If we fail for any reason,
17621774
// just return whatever GetVersion said.
1775+
// UWP return correct version from GetVersionExW, this is not necessary.
17631776
PyObject *realVersion = _sys_getwindowsversion_from_kernel32();
17641777
if (!realVersion) {
17651778
if (!PyErr_ExceptionMatches(PyExc_WindowsError)) {
@@ -1775,6 +1788,7 @@ sys_getwindowsversion_impl(PyObject *module)
17751788
}
17761789

17771790
SET_VERSION_INFO(realVersion);
1791+
#endif
17781792

17791793
#undef SET_VERSION_INFO
17801794

0 commit comments

Comments
 (0)