@@ -894,10 +894,11 @@ Return information about the running version of Windows as a named tuple.\n\
894894The members are named: major, minor, build, platform, service_pack,\n\
895895service_pack_major, service_pack_minor, suite_mask, and product_type. For\n\
896896backward compatibility, only the first 5 items are available by indexing.\n\
897- All elements are numbers, except service_pack which is a string. Platform\n\
898- may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP/Vista/7,\n\
899- 3 for Windows CE. Product_type may be 1 for a workstation, 2 for a domain\n\
900- controller, 3 for a server."
897+ All elements are numbers, except service_pack and platform_type which are\n\
898+ strings, and platform_version which is a 3-tuple. Platform is always 2.\n\
899+ Product_type may be 1 for a workstation, 2 for a domain controller, 3 for a\n\
900+ server. Platform_version is a 3-tuple containing a version number that is\n\
901+ intended for identifying the OS rather than feature detection."
901902);
902903
903904static PyTypeObject WindowsVersionType = {0 , 0 , 0 , 0 , 0 , 0 };
@@ -912,6 +913,7 @@ static PyStructSequence_Field windows_version_fields[] = {
912913 {"service_pack_minor" , "Service Pack minor version number" },
913914 {"suite_mask" , "Bit mask identifying available product suites" },
914915 {"product_type" , "System product type" },
916+ {"platform_version" , "Diagnostic version number" },
915917 {0 }
916918};
917919
@@ -936,6 +938,12 @@ sys_getwindowsversion(PyObject *self)
936938 PyObject * version ;
937939 int pos = 0 ;
938940 OSVERSIONINFOEX ver ;
941+ DWORD realMajor , realMinor , realBuild ;
942+ HANDLE hKernel32 ;
943+ wchar_t kernel32_path [MAX_PATH ];
944+ LPVOID verblock ;
945+ DWORD verblock_size ;
946+
939947 ver .dwOSVersionInfoSize = sizeof (ver );
940948 if (!GetVersionEx ((OSVERSIONINFO * ) & ver ))
941949 return PyErr_SetFromWindowsErr (0 );
@@ -954,10 +962,40 @@ sys_getwindowsversion(PyObject *self)
954962 PyStructSequence_SET_ITEM (version , pos ++ , PyLong_FromLong (ver .wSuiteMask ));
955963 PyStructSequence_SET_ITEM (version , pos ++ , PyLong_FromLong (ver .wProductType ));
956964
965+ realMajor = ver .dwMajorVersion ;
966+ realMinor = ver .dwMinorVersion ;
967+ realBuild = ver .dwBuildNumber ;
968+
969+ // GetVersion will lie if we are running in a compatibility mode.
970+ // We need to read the version info from a system file resource
971+ // to accurately identify the OS version. If we fail for any reason,
972+ // just return whatever GetVersion said.
973+ hKernel32 = GetModuleHandleW (L"kernel32.dll" );
974+ if (hKernel32 && GetModuleFileNameW (hKernel32 , kernel32_path , MAX_PATH ) &&
975+ (verblock_size = GetFileVersionInfoSizeW (kernel32_path , NULL )) &&
976+ (verblock = PyMem_RawMalloc (verblock_size ))) {
977+ VS_FIXEDFILEINFO * ffi ;
978+ UINT ffi_len ;
979+
980+ if (GetFileVersionInfoW (kernel32_path , 0 , verblock_size , verblock ) &&
981+ VerQueryValueW (verblock , L"" , (LPVOID )& ffi , & ffi_len )) {
982+ realMajor = HIWORD (ffi -> dwProductVersionMS );
983+ realMinor = LOWORD (ffi -> dwProductVersionMS );
984+ realBuild = HIWORD (ffi -> dwProductVersionLS );
985+ }
986+ PyMem_RawFree (verblock );
987+ }
988+ PyStructSequence_SET_ITEM (version , pos ++ , PyTuple_Pack (3 ,
989+ PyLong_FromLong (realMajor ),
990+ PyLong_FromLong (realMinor ),
991+ PyLong_FromLong (realBuild )
992+ ));
993+
957994 if (PyErr_Occurred ()) {
958995 Py_DECREF (version );
959996 return NULL ;
960997 }
998+
961999 return version ;
9621000}
9631001
0 commit comments