123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- // +build windows
- package sysinfo
- import sys "core:sys/windows"
- import "base:intrinsics"
- import "core:strings"
- import "core:unicode/utf16"
- import "core:fmt"
- import "base:runtime"
- @(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)
- */
- os_version.platform = .Windows
- 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.major = int(osvi.dwMajorVersion)
- os_version.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) {
- dv, ok := read_reg_string(
- sys.HKEY_LOCAL_MACHINE,
- "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
- "DisplayVersion",
- )
- defer delete(dv) // It'll be interned into `version_string_buf`
- if ok {
- strings.write_string(b, " (version: ")
- l := strings.builder_len(b^)
- strings.write_string(b, dv)
- version = strings.to_string(b^)[l:][:len(dv)]
- strings.write_rune(b, ')')
- }
- return
- }
- // Grab build number and UBR
- format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) {
- res, ok := read_reg_i32(
- sys.HKEY_LOCAL_MACHINE,
- "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
- "UBR",
- )
- if ok {
- ubr = int(res)
- 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),
- }
- }
- @(init, private)
- init_gpu_info :: proc() {
- GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
- gpu_list: [dynamic]GPU
- gpu_index: int
- for {
- key := fmt.tprintf("%v\\%04d", GPU_INFO_BASE, gpu_index)
- if vendor, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "ProviderName"); ok {
- append(&gpu_list, GPU{vendor_name = vendor})
- } else {
- break
- }
- if desc, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc"); ok {
- gpu_list[gpu_index].model_name = desc
- }
- if vram, ok := read_reg_i64(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize"); ok {
- gpu_list[gpu_index].total_ram = int(vram)
- }
- gpu_index += 1
- }
- gpus = gpu_list[:]
- }
- @(private)
- read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok: bool) {
- if len(subkey) == 0 || len(val) == 0 {
- return
- }
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
- BUF_SIZE :: 1024
- key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- utf16.encode_string(key_name_wide, subkey)
- utf16.encode_string(val_name_wide, val)
- result_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- result_size := sys.DWORD(BUF_SIZE * size_of(u16))
- status := sys.RegGetValueW(
- hkey,
- &key_name_wide[0],
- &val_name_wide[0],
- sys.RRF_RT_REG_SZ,
- nil,
- raw_data(result_wide[:]),
- &result_size,
- )
- if status != 0 {
- // Couldn't retrieve string
- return
- }
- // Result string will be allocated for the caller.
- result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator)
- utf16.decode_to_utf8(result_utf8, result_wide[:result_size])
- return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true
- }
- @(private)
- read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool) {
- if len(subkey) == 0 || len(val) == 0 {
- return
- }
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
- BUF_SIZE :: 1024
- key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- utf16.encode_string(key_name_wide, subkey)
- utf16.encode_string(val_name_wide, val)
- result_size := sys.DWORD(size_of(i32))
- status := sys.RegGetValueW(
- hkey,
- &key_name_wide[0],
- &val_name_wide[0],
- sys.RRF_RT_REG_DWORD,
- nil,
- &res,
- &result_size,
- )
- return res, status == 0
- }
- @(private)
- read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool) {
- if len(subkey) == 0 || len(val) == 0 {
- return
- }
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
- BUF_SIZE :: 1024
- key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
- utf16.encode_string(key_name_wide, subkey)
- utf16.encode_string(val_name_wide, val)
- result_size := sys.DWORD(size_of(i64))
- status := sys.RegGetValueW(
- hkey,
- &key_name_wide[0],
- &val_name_wide[0],
- sys.RRF_RT_REG_QWORD,
- nil,
- &res,
- &result_size,
- )
- return res, status == 0
- }
|