Source

check_os / ostype.py

# -*- coding: utf-8 -*-

from ctypes import windll, Structure, sizeof, byref
from ctypes.wintypes import DWORD, WCHAR, WORD, BYTE, LPVOID, POINTER
import win32api
import _winreg
import langcode

VER_NT_WORKSTATION = 1
VER_SUITE_ENTERPRISE = 0x0002
VER_SUITE_DATACENTER = 0x0080
VER_SUITE_PERSONAL = 0x0200
VER_SUITE_BLADE = 0x0400
VER_SUITE_STORAGE_SERVER = 0x2000
VER_SUITE_COMPUTE_SERVER = 0x4000
VER_SUITE_WH_SERVER = 0x8000
PROCESSOR_ARCHITECTURE_IA64 = 6
PROCESSOR_ARCHITECTURE_AMD64 = 9
SM_TABLETPC = 86
SM_MEDIACENTER = 87
SM_STARTER = 88
SM_SERVERR2 = 89

EDITIONS = {
    0x06: "%s Business",
    0x10: "%s Business N",
    0x12: "%s HPC Edition",
    0x08: "%s Datacenter (full installation)",
    0x0C: "%s Datacenter (core installation)",
    0x27: "%s Datacenter without Hyper-V (core installation)",
    0x25: "%s Datacenter without Hyper-V (full installation)",
    0x04: "%s Enterprise",
    0x46: "%s Enterprise E",
    0x1B: "%s Enterprise N",
    0x0A: "%s Enterprise (full installation)",
    0x0E: "%s Enterprise (core installation)",
    0x29: "%s Enterprise without Hyper-V (core installation)",
    0x0F: "%s Enterprise for Itanium-based Systems",
    0x26: "%s Enterprise without Hyper-V (full installation)",
    0x02: "%s Home Basic",
    0x43: "%s Home Basic E",
    0x05: "%s Home Basic N",
    0x03: "%s Home Premium",
    0x44: "%s Home Premium E",
    0x1A: "%s Home Premium N",
    0x2A: "Microsoft Hyper-V %s",
    0x1E: "Windows Essential Business %s Management Server",
    0x20: "Windows Essential Business %s Messaging Server",
    0x1F: "Windows Essential Business %s Security Server",
    0x30: "%s Professional",
    0x45: "%s Professional E",
    0x31: "%s Professional N",
    0x18: "Windows %s for Windows Essential Server Solutions",
    0x23: "Windows %s without Hyper-V for Windows Essential Server Solutions",
    0x21: "%s Foundation",
    0x09: "Windows Small Business %s",
    0x07: "%s Standard (full installation)",
    0x0D: "%s Standard (core installation)",
    0x28: "%s Standard without Hyper-V (core installation)",
    0x24: "%s Standard without Hyper-V (full installation)",
    0x0B: "%s Starter",
    0x42: "%s Starter E",
    0x2F: "%s Starter N",
    0x17: "Storage %s Enterprise",
    0x14: "Storage %s Express",
    0x15: "Storage %s Standard",
    0x16: "Storage %s Workgroup",
    0x00: "%s An unknown product",
    0x01: "%s Ultimate",
    0x47: "%s Ultimate E",
    0x1C: "%s Ultimate N",
    0x11: "Web %s (full installation)",
    0x1D: "Web %s (core installation)",
}

EDITIONS_ = {}
for k, v in EDITIONS.iteritems():
    EDITIONS_[k] = v.replace("%s ", "")

GetSystemMetrics = windll.user32.GetSystemMetrics


class OSVERSIONINFOEX(Structure):
    _fields_ = [
        ('dwOSVersionInfoSize', DWORD),
        ('dwMajorVersion', DWORD),
        ('dwMinorVersion', DWORD),
        ('dwBuildNumber', DWORD),
        ('dwPlatformId', DWORD),
        ('szCSDVersion', WCHAR * 128),
        ('wServicePackMajor', WORD),
        ('wServicePackMinor', WORD),
        ('wSuiteMask', WORD),
        ('wProductType', BYTE),
        ('wReserved', BYTE),
    ]


class SYSTEM_INFO(Structure):
    _fields_ = [
        ('wProcessorArchitecture', WORD),
        ('wReserved', WORD),
        ('dwPageSize', DWORD),
        ('lpMinimumApplicationAddress', LPVOID),
        ('lpMaximumApplicationAddress', LPVOID),
        ('dwActiveProcessorMask', POINTER(DWORD)),
        ('dwNumberOfProcessors', DWORD),
        ('dwProcessorType', DWORD),
        ('dwAllocationGranularity', DWORD),
        ('wProcessorLevel', WORD),
        ('wProcessorRevision', WORD),
    ]


def GetWindowsVersion():
    "returns (os_type, edition, SP, arch)"
    system_info = SYSTEM_INFO()
    osvi = OSVERSIONINFOEX()
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX)
    windll.kernel32.GetVersionExW(byref(osvi))
    try:
        MyGetSystemInfo = windll.kernel32.GetNativeSystemInfo
    except AttributeError:
        MyGetSystemInfo = windll.kernel32.GetSystemInfo
    MyGetSystemInfo(byref(system_info))
    name = []
    major_version = osvi.dwMajorVersion
    minor_version = osvi.dwMinorVersion

    if major_version == 5:
        suiteMask = osvi.wSuiteMask
        if minor_version == 0:
            name.append("2000")
            if osvi.wProductType == VER_NT_WORKSTATION:
                name.append("Professional")
            else:
                if suiteMask & VER_SUITE_DATACENTER:
                    name.append("Datacenter Server")
                elif suiteMask & VER_SUITE_ENTERPRISE:
                    name.append("Advanced Server")
                else:
                    name.append("Server")
        elif minor_version == 1:
            name.append("XP")
            if GetSystemMetrics(SM_MEDIACENTER):
                name.append("Media Center Edition")
            elif GetSystemMetrics(SM_TABLETPC):
                name.append("Tablet PC Edition")
            elif GetSystemMetrics(SM_STARTER):
                name.append("Starter Edition")
            elif suiteMask & VER_SUITE_PERSONAL:
                name.append("Home Edition")
            else:
                name.append("Professional")
        elif minor_version == 2:
            if GetSystemMetrics(SM_SERVERR2):
                name.append("Server 2003 R2")
            elif suiteMask == VER_SUITE_STORAGE_SERVER:
                name.append("Storage Server 2003")
            elif suiteMask == VER_SUITE_WH_SERVER:
                name.append("Home Server")
            elif osvi.wProductType == VER_NT_WORKSTATION:
                # Windows XP Professional x64 Edition
                name.extend(["XP", "Professional"])
            else:
                name.append("Server 2003")
            if osvi.wProductType != VER_NT_WORKSTATION:
                if suiteMask & VER_SUITE_COMPUTE_SERVER:
                    name.append("Compute Cluster Edition")
                elif suiteMask & VER_SUITE_DATACENTER:
                    name.append("Datacenter Edition")
                elif suiteMask & VER_SUITE_ENTERPRISE:
                    name.append("Enterprise Edition")
                elif suiteMask & VER_SUITE_BLADE:
                    name.append("Web Edition")
                else:
                    name.append("Standard Edition")
    elif major_version == 6:
        try:
            os_type = {
                (0, True): "Vista",
                (0, False): "Server 2008",
                (1, True): "7",
                (1, False): "Server 2008 R2",
            }[(minor_version, osvi.wProductType == VER_NT_WORKSTATION)]
        except KeyError:
            os_type = "Unknown OS 6.%d" % minor_version
        dwType = DWORD()
        windll.kernel32.GetProductInfo(
            major_version, minor_version, 0, 0, byref(dwType)
        )
        try:
            #name = EDITIONS[dwType.value] % os_type
            name = [os_type, EDITIONS_[dwType.value]]
        except KeyError:
            #name = "%s (Unknown Edition %d)" % (os_type, dwType.value)
            name = [os_type, "(Unknown Edition %d)" % dwType.value]

    if osvi.wServicePackMajor:
        spname = "SP%d" % osvi.wServicePackMajor
        if osvi.wServicePackMinor:
            spname += ".%d" % osvi.wServicePackMinor
        name.append(spname)
    else:
        name.append(None)

    if system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64:
        name.append("64-bit")
    elif system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64:
        name.append("Itanium")
    else:
        name.append("32-bit")
    #name.append("(build %d)" % osvi.dwBuildNumber)
    #return "Microsoft Windows " + name
    return tuple(name)

def GetWindowsLanguage():
    r"""Get OS language from registry.
    HKLM\SYSTEM\ControlSet001\Control\Nls\Language\InstallLanguage"""
    hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
            r'SYSTEM\ControlSet001\Control\Nls\Language')
    value, type = _winreg.QueryValueEx(hkey, r'InstallLanguage')
    lang_id = int(value, 16)
    return id2desc(lang_id)

def GetWindowsLanguage2():
    """Get windows language settings from control panel.
    Don't use this to get system language. It may be inacurate."""
    lang_id = win32api.GetSystemDefaultLangID()
    return id2desc(lang_id)

def id2desc(id):
    '''id2desc(id) -> desc
    '''
    for k, v in langcode.code.iteritems():
        if id == k:
            return v
    raise IndexError("Description not found for Language ID %d" % id)

def GetWindowsMUI():
    """Returns a list of installed MUI language packs"""
    mui_keystr = r'SYSTEM\ControlSet001\Control\MUI\UILanguages'
    try:
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, mui_keystr)
    except WindowsError:
        return []
    i = 0
    mui_lang_ids = []
    while True:
        try:
            subkey = _winreg.EnumKey(hkey, i)
            i += 1
        except WindowsError:
            break
        subkeystr = mui_keystr + '\\' + subkey
        h_muikey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkeystr)
        value, type = _winreg.QueryValueEx(h_muikey, 'LCID')
        mui_lang_ids.append(value)

    os_mui = [id2desc(id) for id in mui_lang_ids]
    os_mui.sort(key=lambda x: x[0])
    return os_mui

# Test
if __name__ == "__main__":
    print "Windows version:", GetWindowsVersion()
    print "Installed language:", GetWindowsLanguage()
    print "System language ID:", GetWindowsLanguage2()
    mui = GetWindowsMUI()
    if mui:
        print "MUI Info:"
        for (lang, region) in mui:
            print "%s - %s" % (lang, region)