diff --git a/core/sys/info/cpu_arm.odin b/core/sys/info/cpu_arm.odin new file mode 100644 index 000000000..5a56e3f78 --- /dev/null +++ b/core/sys/info/cpu_arm.odin @@ -0,0 +1,26 @@ +//+build arm32, arm64 +package sysinfo + +// TODO: Set up an enum with the ARM equivalent of the above. +CPU_Feature :: enum u64 {} + +cpu_features: Maybe(CPU_Feature) +cpu_name: Maybe(string) + +@(init, private) +init_cpu_features :: proc "c" () { +} + +@(private) +_cpu_name_buf: [72]u8 + +@(init, private) +init_cpu_name :: proc "c" () { + when ODIN_ARCH == .arm32 { + copy(_cpu_name_buf, "ARM") + cpu_name = string(_cpu_name_buf[:3]) + } else { + copy(_cpu_name_buf, "ARM64") + cpu_name = string(_cpu_name_buf[:5]) + } +} \ No newline at end of file diff --git a/core/simd/x86/cpu.odin b/core/sys/info/cpu_intel.odin similarity index 75% rename from core/simd/x86/cpu.odin rename to core/sys/info/cpu_intel.odin index 14e90c0f0..eeb9c2416 100644 --- a/core/simd/x86/cpu.odin +++ b/core/sys/info/cpu_intel.odin @@ -1,5 +1,5 @@ //+build i386, amd64 -package simd_x86 +package sysinfo import "core:intrinsics" @@ -9,7 +9,6 @@ cpuid :: intrinsics.x86_cpuid // xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- xgetbv :: intrinsics.x86_xgetbv - CPU_Feature :: enum u64 { aes, // AES hardware implementation (AES NI) adx, // Multi-precision add-carry instruction extensions @@ -34,6 +33,7 @@ CPU_Feature :: enum u64 { CPU_Features :: distinct bit_set[CPU_Feature; u64] cpu_features: Maybe(CPU_Features) +cpu_name: Maybe(string) @(init, private) init_cpu_features :: proc "c" () { @@ -92,3 +92,31 @@ init_cpu_features :: proc "c" () { cpu_features = set } + +@(private) +_cpu_name_buf: [72]u8 + +@(init, private) +init_cpu_name :: proc "c" () { + number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0) + if number_of_extended_ids < 0x8000_0004 { + return + } + + _buf := transmute(^[0x12]u32)&_cpu_name_buf + _buf[ 0], _buf[ 1], _buf[ 2], _buf[ 3] = cpuid(0x8000_0002, 0) + _buf[ 4], _buf[ 5], _buf[ 6], _buf[ 7] = cpuid(0x8000_0003, 0) + _buf[ 8], _buf[ 9], _buf[10], _buf[11] = cpuid(0x8000_0004, 0) + + // Some CPUs like may include leading or trailing spaces. Trim them. + // e.g. ` Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz` + + brand := string(_cpu_name_buf[:]) + for len(brand) > 0 && brand[0] == 0 || brand[0] == ' ' { + brand = brand[1:] + } + for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' { + brand = brand[:len(brand) - 1] + } + cpu_name = brand +} \ No newline at end of file diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin new file mode 100644 index 000000000..0cdfd455d --- /dev/null +++ b/core/sys/info/platform_darwin.odin @@ -0,0 +1,33 @@ +// +build darwin +package sysinfo + +import sys "core:sys/darwin" +import "core:intrinsics" + +@(init, private) +init_os_version :: proc "c" () { + os_version = {} +} + +@(init) +init_ram :: proc() { + // Retrieve RAM info using `sysinfo` + + CTL_HW :: 6 + HW_MEMSIZE :: 24 + + sysctls := []int{CTL_HW, HW_MEMSIZE} + + mem_size: i64 + + if intrinsics.syscall( + uintptr(sys.System_Call_Number.sysctl), + uintptr(raw_data(sysctls)), uintptr(len(sysctls)), + uintptr(&mem_size), uintptr(size_of(mem_size))) == 0 { + return + } + ram.total_ram = int(mem_size) +} + +@(private) +sysctl :: proc(leaf: int) \ No newline at end of file diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin new file mode 100644 index 000000000..05f263094 --- /dev/null +++ b/core/sys/info/platform_linux.odin @@ -0,0 +1,54 @@ +// +build linux +package sysinfo + +import "core:c" +import sys "core:sys/unix" +import "core:intrinsics" +// import "core:fmt" + +@(init, private) +init_os_version :: proc "c" () { + os_version = {} +} + +Sys_Info :: struct { + uptime: c.long, // Seconds since boot + loads: [3]c.long, // 1, 5, 15 minute load averages + totalram: c.ulong, // Total usable main memory size + freeram: c.ulong, // Available memory size + sharedram: c.ulong, // Amount of shared memory + bufferram: c.ulong, // Memory used by buffers + totalswap: c.ulong, // Total swap space size + freeswap: c.ulong, // Swap space still available + procs: c.ushort, // Number of current processes + totalhigh: c.ulong, // Total high memory size + freehigh: c.ulong, // Available high memory size + mem_unit: c.int, // Memory unit size in bytes + _padding: [20 - (2 * size_of(c.long)) - size_of(c.int)]u8, +} + +get_sysinfo :: proc "c" () -> (res: Sys_Info, ok: bool) { + si: Sys_Info + err := intrinsics.syscall(sys.SYS_sysinfo, uintptr(rawptr(&si))) + if err != 0 { + // Unable to retrieve sysinfo + return {}, false + } + return si, true +} + +@(init) +init_ram :: proc() { + // Retrieve RAM info using `sysinfo` + si, ok := get_sysinfo() + if !ok { + return + } + + ram = RAM{ + total_ram = int(si.totalram) * int(si.mem_unit), + free_ram = int(si.freeram) * int(si.mem_unit), + total_swap = int(si.totalswap) * int(si.mem_unit), + free_swap = int(si.freeswap) * int(si.mem_unit), + } +} \ No newline at end of file diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin new file mode 100644 index 000000000..e5ce7f3c8 --- /dev/null +++ b/core/sys/info/platform_windows.odin @@ -0,0 +1,305 @@ +// +build windows +package sysinfo + +import sys "core:sys/windows" +import "core:intrinsics" +import "core:strings" + + +@(private) +version_string_buf: [1024]u8 + +@(init, private) +init_os_version :: proc () { + /* + NOTE(Jeroen): + `GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10. + `RtlGetVersion` will return the true version. + + Rather than include the WinDDK, we ask the kernel directly. + `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion` is for the minor build version (Update Build Release) + + */ + osvi: sys.OSVERSIONINFOEXW + osvi.dwOSVersionInfoSize = size_of(osvi) + status := sys.RtlGetVersion(&osvi) + + if status != 0 { + return + } + + product_type: sys.Windows_Product_Type + sys.GetProductInfo( + osvi.dwMajorVersion, osvi.dwMinorVersion, + u32(osvi.wServicePackMajor), u32(osvi.wServicePackMinor), + &product_type, + ) + + os_version = { + platform = .Windows, + major = int(osvi.dwMajorVersion), + minor = int(osvi.dwMinorVersion), + } + os_version.build[0] = int(osvi.dwBuildNumber) + + b := strings.builder_from_bytes(version_string_buf[:]) + + strings.write_string(&b, "Windows ") + + switch osvi.dwMajorVersion { + case 10: + switch osvi.wProductType { + case 1: // VER_NT_WORKSTATION: + if osvi.dwBuildNumber < 22000 { + strings.write_string(&b, "10 ") + } else { + strings.write_string(&b, "11 ") + } + format_windows_product_type(&b, product_type) + + case: // Server or Domain Controller + switch osvi.dwBuildNumber { + case 14393: + strings.write_string(&b, "2016 Server") + case 17763: + strings.write_string(&b, "2019 Server") + case 20348: + strings.write_string(&b, "2022 Server") + case: + strings.write_string(&b, "Unknown Server") + } + } + + case 6: + switch osvi.dwMinorVersion { + case 0: + switch osvi.wProductType { + case 1: // VER_NT_WORKSTATION + strings.write_string(&b, "Windows Vista ") + format_windows_product_type(&b, product_type) + case 3: + strings.write_string(&b, "Windows Server 2008") + } + + case 1: + switch osvi.wProductType { + case 1: // VER_NT_WORKSTATION: + strings.write_string(&b, "Windows 7 ") + format_windows_product_type(&b, product_type) + case 3: + strings.write_string(&b, "Windows Server 2008 R2") + } + + case 2: + switch osvi.wProductType { + case 1: // VER_NT_WORKSTATION: + strings.write_string(&b, "Windows 8 ") + format_windows_product_type(&b, product_type) + case 3: + strings.write_string(&b, "Windows Server 2012") + } + + case 3: + switch osvi.wProductType { + case 1: // VER_NT_WORKSTATION: + strings.write_string(&b, "Windows 8.1 ") + format_windows_product_type(&b, product_type) + case 3: + strings.write_string(&b, "Windows Server 2012 R2") + } + } + + case 5: + switch osvi.dwMinorVersion { + case 0: + strings.write_string(&b, "Windows 2000") + case 1: + strings.write_string(&b, "Windows XP") + case 2: + strings.write_string(&b, "Windows Server 2003") + } + } + + // Grab DisplayVersion + os_version.version = format_display_version(&b) + + // Grab build number and UBR + os_version.build[1] = format_build_number(&b, int(osvi.dwBuildNumber)) + + // Finish the string + os_version.as_string = strings.to_string(b) + + format_windows_product_type :: proc (b: ^strings.Builder, prod_type: sys.Windows_Product_Type) { + #partial switch prod_type { + case .ULTIMATE: + strings.write_string(b, "Ultimate") + + case .HOME_BASIC: + strings.write_string(b, "Home Basic") + + case .HOME_PREMIUM: + strings.write_string(b, "Home Premium") + + case .ENTERPRISE: + strings.write_string(b, "Enterprise") + + case .CORE: + strings.write_string(b, "Home Basic") + + case .HOME_BASIC_N: + strings.write_string(b, "Home Basic N") + + case .EDUCATION: + strings.write_string(b, "Education") + + case .EDUCATION_N: + strings.write_string(b, "Education N") + + case .BUSINESS: + strings.write_string(b, "Business") + + case .STANDARD_SERVER: + strings.write_string(b, "Standard Server") + + case .DATACENTER_SERVER: + strings.write_string(b, "Datacenter") + + case .SMALLBUSINESS_SERVER: + strings.write_string(b, "Windows Small Business Server") + + case .ENTERPRISE_SERVER: + strings.write_string(b, "Enterprise Server") + + case .STARTER: + strings.write_string(b, "Starter") + + case .DATACENTER_SERVER_CORE: + strings.write_string(b, "Datacenter Server Core") + + case .STANDARD_SERVER_CORE: + strings.write_string(b, "Server Standard Core") + + case .ENTERPRISE_SERVER_CORE: + strings.write_string(b, "Enterprise Server Core") + + case .BUSINESS_N: + strings.write_string(b, "Business N") + + case .HOME_SERVER: + strings.write_string(b, "Home Server") + + case .SERVER_FOR_SMALLBUSINESS: + strings.write_string(b, "Windows Server 2008 for Windows Essential Server Solutions") + + case .SMALLBUSINESS_SERVER_PREMIUM: + strings.write_string(b, "Small Business Server Premium") + + case .HOME_PREMIUM_N: + strings.write_string(b, "Home Premium N") + + case .ENTERPRISE_N: + strings.write_string(b, "Enterprise N") + + case .ULTIMATE_N: + strings.write_string(b, "Ultimate N") + + case .HYPERV: + strings.write_string(b, "HyperV") + + case .STARTER_N: + strings.write_string(b, "Starter N") + + case .PROFESSIONAL: + strings.write_string(b, "Professional") + + case .PROFESSIONAL_N: + strings.write_string(b, "Professional N") + + case: + strings.write_string(b, "Unknown Edition") + } + } + + // Grab Windows DisplayVersion (like 20H02) + format_display_version :: proc (b: ^strings.Builder) -> (version: string) { + value_type: ^sys.DWORD + display_version: [256]u16le + value_size := sys.DWORD(size_of(display_version)) + + status := sys.RegGetValueW( + sys.HKEY_LOCAL_MACHINE, + sys.L("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), + sys.L("DisplayVersion"), + sys.RRF_RT_REG_SZ, + value_type, + raw_data(display_version[:]), + &value_size, + ) + if status != 0 { + // Couldn't retrieve DisplayVersion + return + } + + strings.write_string(b, " (version: ") + l := strings.builder_len(b^) + + for r, i in display_version { + if r == 0 { + s := strings.to_string(b^) + version = string(s[l:][:i]) + break + } + if r < 256 { + strings.write_rune(b, rune(r)) + } + } + strings.write_rune(b, ')') + return + } + + // Grab build number and UBR + format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) { + value_type: ^sys.DWORD + _ubr: sys.DWORD + value_size := sys.DWORD(size_of(ubr)) + + status := sys.RegGetValueW( + sys.HKEY_LOCAL_MACHINE, + sys.L("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), + sys.L("UBR"), + sys.RRF_RT_REG_DWORD, + value_type, + &_ubr, + &value_size, + ) + + if status != 0 { + // Couldn't retrieve DisplayVersion + return + } + + ubr = int(_ubr) + strings.write_string(b, ", build: ") + strings.write_int(b, major_build) + strings.write_rune(b, '.') + strings.write_int(b, ubr) + return + } +} + +@(init) +init_ram :: proc() { + state: sys.MEMORYSTATUSEX + + state.dwLength = size_of(state) + ok := sys.GlobalMemoryStatusEx(&state) + if !ok { + return + } + ram = RAM{ + total_ram = int(state.ullTotalPhys), + free_ram = int(state.ullAvailPhys), + total_swap = int(state.ullTotalPageFil), + free_swap = int(state.ullAvailPageFil), + } +} \ No newline at end of file diff --git a/core/sys/info/sysinfo.odin b/core/sys/info/sysinfo.odin new file mode 100644 index 000000000..808f0484d --- /dev/null +++ b/core/sys/info/sysinfo.odin @@ -0,0 +1,38 @@ +package sysinfo + +when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64) { + #assert(false, "This package is unsupported on this architecture.") +} + +os_version: OS_Version +ram: RAM + +OS_Version_Platform :: enum { + Unknown, + Windows, + Linux, + MacOS, + iOS, + FreeBSD, + OpenBSD, + NetBSD, +} + +OS_Version :: struct { + platform: OS_Version_Platform, + + major: int, + minor: int, + patch: int, + build: [2]int, + version: string, + + as_string: string, +} + +RAM :: struct { + total_ram: int, + free_ram: int, + total_swap: int, + free_swap: int, +} \ No newline at end of file diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index f055b6908..03fc295dc 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -637,6 +637,13 @@ foreign kernel32 { ) -> BOOL --- } +@(default_calling_convention="stdcall") +foreign kernel32 { + GlobalMemoryStatusEx :: proc( + lpBuffer: ^MEMORYSTATUSEX, + ) -> BOOL --- +} + PBAD_MEMORY_CALLBACK_ROUTINE :: #type proc "stdcall" () @(default_calling_convention="stdcall") @@ -794,3 +801,14 @@ Control_Event :: enum DWORD { logoff = 5, shutdown = 6, } + +@(default_calling_convention="stdcall") +foreign kernel32 { + GetProductInfo :: proc( + OSMajorVersion: DWORD, + OSMinorVersion: DWORD, + SpMajorVersion: DWORD, + SpMinorVersion: DWORD, + product_type: ^Windows_Product_Type, + ) -> BOOL --- +} \ No newline at end of file diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index edf6e593e..1ddbe5bad 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -17,6 +17,7 @@ size_t :: c.size_t wchar_t :: c.wchar_t DWORD :: c_ulong +DWORDLONG :: c.ulonglong QWORD :: c.ulonglong HANDLE :: distinct LPVOID HINSTANCE :: HANDLE @@ -3265,3 +3266,116 @@ IFileSaveDialogVtbl :: struct { GetProperties: proc "stdcall" (this: ^IFileSaveDialog, ppStore: ^^IPropertyStore) -> HRESULT, ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT, } + +MEMORYSTATUSEX :: struct { + dwLength: DWORD, + dwMemoryLoad: DWORD, + ullTotalPhys: DWORDLONG, + ullAvailPhys: DWORDLONG, + ullTotalPageFil: DWORDLONG, + ullAvailPageFil: DWORDLONG, + ullTotalVirtual: DWORDLONG, + ullAvailVirtual: DWORDLONG, + ullAvailExtendedVirtual: DWORDLONG, +} + +Windows_Product_Type :: enum DWORD { + BUSINESS = 0x00000006, // Business + BUSINESS_N = 0x00000010, // Business N + CLUSTER_SERVER = 0x00000012, // HPC Edition + CLUSTER_SERVER_V = 0x00000040, // Server Hyper Core V + CORE = 0x00000065, // Windows 10 Home + CORE_COUNTRYSPECIFIC = 0x00000063, // Windows 10 Home China + CORE_N = 0x00000062, // Windows 10 Home N + CORE_SINGLELANGUAGE = 0x00000064, // Windows 10 Home Single Language + DATACENTER_EVALUATION_SERVER = 0x00000050, // Server Datacenter (evaluation installation) + DATACENTER_A_SERVER_CORE = 0x00000091, // Server Datacenter, Semi-Annual Channel (core installation) + STANDARD_A_SERVER_CORE = 0x00000092, // Server Standard, Semi-Annual Channel (core installation) + DATACENTER_SERVER = 0x00000008, // Server Datacenter (full installation. For Server Core installations of Windows Server 2012 and later, use the method, Determining whether Server Core is running.) + DATACENTER_SERVER_CORE = 0x0000000C, // Server Datacenter (core installation, Windows Server 2008 R2 and earlier) + DATACENTER_SERVER_CORE_V = 0x00000027, // Server Datacenter without Hyper-V (core installation) + DATACENTER_SERVER_V = 0x00000025, // Server Datacenter without Hyper-V (full installation) + EDUCATION = 0x00000079, // Windows 10 Education + EDUCATION_N = 0x0000007A, // Windows 10 Education N + ENTERPRISE = 0x00000004, // Windows 10 Enterprise + ENTERPRISE_E = 0x00000046, // Windows 10 Enterprise E + ENTERPRISE_EVALUATION = 0x00000048, // Windows 10 Enterprise Evaluation + ENTERPRISE_N = 0x0000001B, // Windows 10 Enterprise N + ENTERPRISE_N_EVALUATION = 0x00000054, // Windows 10 Enterprise N Evaluation + ENTERPRISE_S = 0x0000007D, // Windows 10 Enterprise 2015 LTSB + ENTERPRISE_S_EVALUATION = 0x00000081, // Windows 10 Enterprise 2015 LTSB Evaluation + ENTERPRISE_S_N = 0x0000007E, // Windows 10 Enterprise 2015 LTSB N + ENTERPRISE_S_N_EVALUATION = 0x00000082, // Windows 10 Enterprise 2015 LTSB N Evaluation + ENTERPRISE_SERVER = 0x0000000A, // Server Enterprise (full installation) + ENTERPRISE_SERVER_CORE = 0x0000000E, // Server Enterprise (core installation) + ENTERPRISE_SERVER_CORE_V = 0x00000029, // Server Enterprise without Hyper-V (core installation) + ENTERPRISE_SERVER_IA64 = 0x0000000F, // Server Enterprise for Itanium-based Systems + ENTERPRISE_SERVER_V = 0x00000026, // Server Enterprise without Hyper-V (full installation) + ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C, // Windows Essential Server Solution Additional + ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E, // Windows Essential Server Solution Additional SVC + ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B, // Windows Essential Server Solution Management + ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D, // Windows Essential Server Solution Management SVC + HOME_BASIC = 0x00000002, // Home Basic + HOME_BASIC_E = 0x00000043, // Not supported + HOME_BASIC_N = 0x00000005, // Home Basic N + HOME_PREMIUM = 0x00000003, // Home Premium + HOME_PREMIUM_E = 0x00000044, // Not supported + HOME_PREMIUM_N = 0x0000001A, // Home Premium N + HOME_PREMIUM_SERVER = 0x00000022, // Windows Home Server 2011 + HOME_SERVER = 0x00000013, // Windows Storage Server 2008 R2 Essentials + HYPERV = 0x0000002A, // Microsoft Hyper-V Server + IOTENTERPRISE = 0x000000BC, // Windows IoT Enterprise + IOTENTERPRISE_S = 0x000000BF, // Windows IoT Enterprise LTSC + IOTUAP = 0x0000007B, // Windows 10 IoT Core + IOTUAPCOMMERCIAL = 0x00000083, // Windows 10 IoT Core Commercial + MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E, // Windows Essential Business Server Management Server + MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020, // Windows Essential Business Server Messaging Server + MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F, // Windows Essential Business Server Security Server + MOBILE_CORE = 0x00000068, // Windows 10 Mobile + MOBILE_ENTERPRISE = 0x00000085, // Windows 10 Mobile Enterprise + MULTIPOINT_PREMIUM_SERVER = 0x0000004D, // Windows MultiPoint Server Premium (full installation) + MULTIPOINT_STANDARD_SERVER = 0x0000004C, // Windows MultiPoint Server Standard (full installation) + PRO_WORKSTATION = 0x000000A1, // Windows 10 Pro for Workstations + PRO_WORKSTATION_N = 0x000000A2, // Windows 10 Pro for Workstations N + PROFESSIONAL = 0x00000030, // Windows 10 Pro + PROFESSIONAL_E = 0x00000045, // Not supported + PROFESSIONAL_N = 0x00000031, // Windows 10 Pro N + PROFESSIONAL_WMC = 0x00000067, // Professional with Media Center + SB_SOLUTION_SERVER = 0x00000032, // Windows Small Business Server 2011 Essentials + SB_SOLUTION_SERVER_EM = 0x00000036, // Server For SB Solutions EM + SERVER_FOR_SB_SOLUTIONS = 0x00000033, // Server For SB Solutions + SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037, // Server For SB Solutions EM + SERVER_FOR_SMALLBUSINESS = 0x00000018, // Windows Server 2008 for Windows Essential Server Solutions + SERVER_FOR_SMALLBUSINESS_V = 0x00000023, // Windows Server 2008 without Hyper-V for Windows Essential Server Solutions + SERVER_FOUNDATION = 0x00000021, // Server Foundation + SMALLBUSINESS_SERVER = 0x00000009, // Windows Small Business Server + SMALLBUSINESS_SERVER_PREMIUM = 0x00000019, // Small Business Server Premium + SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F, // Small Business Server Premium (core installation) + SOLUTION_EMBEDDEDSERVER = 0x00000038, // Windows MultiPoint Server + STANDARD_EVALUATION_SERVER = 0x0000004F, // Server Standard (evaluation installation) + STANDARD_SERVER = 0x00000007, // Server Standard (full installation. For Server Core installations of Windows Server 2012 and later, use the method, Determining whether Server Core is running.) + STANDARD_SERVER_CORE = 0x0000000D, // Server Standard (core installation, Windows Server 2008 R2 and earlier) + STANDARD_SERVER_CORE_V = 0x00000028, // Server Standard without Hyper-V (core installation) + STANDARD_SERVER_V = 0x00000024, // Server Standard without Hyper-V + STANDARD_SERVER_SOLUTIONS = 0x00000034, // Server Solutions Premium + STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035, // Server Solutions Premium (core installation) + STARTER = 0x0000000B, // Starter + STARTER_E = 0x00000042, // Not supported + STARTER_N = 0x0000002F, // Starter N + STORAGE_ENTERPRISE_SERVER = 0x00000017, // Storage Server Enterprise + STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E, // Storage Server Enterprise (core installation) + STORAGE_EXPRESS_SERVER = 0x00000014, // Storage Server Express + STORAGE_EXPRESS_SERVER_CORE = 0x0000002B, // Storage Server Express (core installation) + STORAGE_STANDARD_EVALUATION_SERVER = 0x00000060, // Storage Server Standard (evaluation installation) + STORAGE_STANDARD_SERVER = 0x00000015, // Storage Server Standard + STORAGE_STANDARD_SERVER_CORE = 0x0000002C, // Storage Server Standard (core installation) + STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F, // Storage Server Workgroup (evaluation installation) + STORAGE_WORKGROUP_SERVER = 0x00000016, // Storage Server Workgroup + STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D, // Storage Server Workgroup (core installation) + ULTIMATE = 0x00000001, // Ultimate + ULTIMATE_E = 0x00000047, // Not supported + ULTIMATE_N = 0x0000001C, // Ultimate N + UNDEFINED = 0x00000000, // An unknown product + WEB_SERVER = 0x00000011, // Web Server (full installation) + WEB_SERVER_CORE = 0x0000001D, // Web Server (core installation) +} \ No newline at end of file