_WIN32_CLIENT_RELEASES = { (6, 0): "Vista", (6, 1): "7", (6, 2): "8", (6, 3): "8.1", (6, None): "post8.1", (10, 0): "10", (10, None): "post10", } # Server release name lookup will default to client names if necessary _WIN32_SERVER_RELEASES = { (6, 0): "2008Server", (6, 1): "2008ServerR2", (6, 2): "2012Server", (6, 3): "2012ServerR2", (6, None): "post2012ServerR2", } def win32_ver(release='', version='', csd='', ptype=''): from ctypes import byref, cast, POINTER, Structure, WinDLL from ctypes import create_unicode_buffer, c_buffer from ctypes.wintypes import DWORD from sys import getwindowsversion from winreg import QueryValueEx, OpenKeyEx, CloseKey, HKEY_LOCAL_MACHINE class VS_FIXEDFILEINFO(Structure): _fields_ = [ ("dwSignature", DWORD), ("dwStrucVersion", DWORD), ("dwFileVersionMS", DWORD), ("dwFileVersionLS", DWORD), ("dwProductVersionMS", DWORD), ("dwProductVersionLS", DWORD), ("dwFileFlagsMask", DWORD), ("dwFileFlags", DWORD), ("dwFileOS", DWORD), ("dwFileType", DWORD), ("dwFileSubtype", DWORD), ("dwFileDateMS", DWORD), ("dwFileDateLS", DWORD), ] kernel32 = WinDLL('kernel32') version = WinDLL('version') # We will immediately double the length up to MAX_PATH, but the # path may be longer, so we retry until the returned string is # shorter than our buffer. name_len = actual_len = 130 while actual_len == name_len: name_len *= 2 name = create_unicode_buffer(name_len) actual_len = kernel32.GetModuleFileNameW(kernel32._handle, name, len(name)) if not actual_len: return release, version, csd, ptype size = version.GetFileVersionInfoSizeW(name, None) if not size: return release, version, csd, ptype ver_block = byref(c_buffer(size)) if not version.GetFileVersionInfoW(name, None, size, ver_block) or not ver_block: return release, version, csd, ptype pvi = POINTER(VS_FIXEDFILEINFO)() if not version.VerQueryValueW(ver_block, "\\", byref(pvi), byref(DWORD())): return release, version, csd, ptype maj = int(pvi.contents.dwProductVersionMS >> 16) min = int(pvi.contents.dwProductVersionMS & 0xFFFF) build = int(pvi.contents.dwProductVersionLS >> 16) version = '{0}.{1}.{2}'.format(maj, min, build) release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or _WIN32_CLIENT_RELEASES.get((maj, None)) or release) winver = getwindowsversion() # 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] == (maj, min): try: csd = 'SP{}'.format(winver.service_pack_major) except AttributeError: if csd[:13] == 'Service Pack ': csd = 'SP' + csd[13:] # VER_NT_SERVER = 3 if getattr(winver, 'product_type', None) == 3: release = (_WIN32_SERVER_RELEASES.get((maj, min)) or _WIN32_SERVER_RELEASES.get((maj, None)) or release) key = None try: key = OpenKeyEx(HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') ptype = QueryValueEx(key, 'CurrentType')[0] except: pass finally: if key: CloseKey(key) return release, version, csd, ptype