196 lines
4.3 KiB
Go
196 lines
4.3 KiB
Go
//go:build windows
|
|
|
|
package sysinfo
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
"golang.org/x/sys/windows/registry"
|
|
)
|
|
|
|
func collectPlatform() Info {
|
|
percent, charging := batteryStatus()
|
|
return Info{
|
|
CPU: cpuName(),
|
|
GPU: gpuName(),
|
|
RAM: totalRAM(),
|
|
BatteryPercent: percent,
|
|
BatteryCharging: charging,
|
|
}
|
|
}
|
|
|
|
func OSName() string {
|
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE,
|
|
`SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
|
if err != nil {
|
|
return "Windows"
|
|
}
|
|
defer k.Close()
|
|
|
|
product, _, _ := k.GetStringValue("ProductName")
|
|
display, _, _ := k.GetStringValue("DisplayVersion")
|
|
build, _, _ := k.GetStringValue("CurrentBuildNumber")
|
|
|
|
name := strings.TrimSpace(product)
|
|
if name == "" {
|
|
name = "Windows"
|
|
}
|
|
var buildNumber int
|
|
_, _ = fmt.Sscanf(strings.TrimSpace(build), "%d", &buildNumber)
|
|
if buildNumber >= 22000 && !strings.Contains(name, "11") {
|
|
name = strings.Replace(name, "Windows 10", "Windows 11", 1)
|
|
if !strings.Contains(name, "11") {
|
|
name = "Windows 11"
|
|
}
|
|
}
|
|
if display = strings.TrimSpace(display); display != "" {
|
|
name += " " + display
|
|
}
|
|
return name
|
|
}
|
|
|
|
func batteryStatus() (*int, bool) {
|
|
type systemPowerStatus struct {
|
|
ACLineStatus byte
|
|
BatteryFlag byte
|
|
BatteryLifePercent byte
|
|
SystemStatusFlag byte
|
|
BatteryLifeTime uint32
|
|
BatteryFullLifeTime uint32
|
|
}
|
|
|
|
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
|
getSystemPowerStatus := kernel32.NewProc("GetSystemPowerStatus")
|
|
var status systemPowerStatus
|
|
ret, _, _ := getSystemPowerStatus.Call(uintptr(unsafe.Pointer(&status)))
|
|
if ret == 0 || status.BatteryLifePercent == 255 || status.BatteryFlag == 128 {
|
|
return nil, false
|
|
}
|
|
percent := int(status.BatteryLifePercent)
|
|
if percent < 0 || percent > 100 {
|
|
return nil, false
|
|
}
|
|
return &percent, status.ACLineStatus == 1
|
|
}
|
|
|
|
func cpuName() string {
|
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE,
|
|
`HARDWARE\DESCRIPTION\System\CentralProcessor\0`, registry.QUERY_VALUE)
|
|
if err != nil {
|
|
return "unknown"
|
|
}
|
|
defer k.Close()
|
|
name, _, err := k.GetStringValue("ProcessorNameString")
|
|
if err != nil {
|
|
return "unknown"
|
|
}
|
|
return strings.TrimSpace(name)
|
|
}
|
|
|
|
func gpuName() string {
|
|
basePath := `SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}`
|
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, basePath, registry.ENUMERATE_SUB_KEYS)
|
|
if err != nil {
|
|
return "unknown"
|
|
}
|
|
defer k.Close()
|
|
|
|
subkeys, err := k.ReadSubKeyNames(-1)
|
|
if err != nil {
|
|
return "unknown"
|
|
}
|
|
|
|
var gpus []string
|
|
for _, sub := range subkeys {
|
|
if len(sub) != 4 {
|
|
continue
|
|
}
|
|
allDigits := true
|
|
for _, c := range sub {
|
|
if c < '0' || c > '9' {
|
|
allDigits = false
|
|
break
|
|
}
|
|
}
|
|
if !allDigits {
|
|
continue
|
|
}
|
|
|
|
sk, err := registry.OpenKey(registry.LOCAL_MACHINE,
|
|
basePath+`\`+sub, registry.QUERY_VALUE)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
desc, _, err := sk.GetStringValue("DriverDesc")
|
|
sk.Close()
|
|
if err != nil || desc == "" {
|
|
continue
|
|
}
|
|
gpus = append(gpus, strings.TrimSpace(desc))
|
|
}
|
|
|
|
if len(gpus) == 0 {
|
|
return "unknown"
|
|
}
|
|
return strings.Join(gpus, ", ")
|
|
}
|
|
|
|
func totalRAM() string {
|
|
type memoryStatusEx struct {
|
|
Length uint32
|
|
MemoryLoad uint32
|
|
TotalPhys uint64
|
|
AvailPhys uint64
|
|
TotalPageFile uint64
|
|
AvailPageFile uint64
|
|
TotalVirtual uint64
|
|
AvailVirtual uint64
|
|
AvailExtendedVirtual uint64
|
|
}
|
|
|
|
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
|
globalMemoryStatusEx := kernel32.NewProc("GlobalMemoryStatusEx")
|
|
|
|
var ms memoryStatusEx
|
|
ms.Length = uint32(unsafe.Sizeof(ms))
|
|
|
|
ret, _, _ := globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&ms)))
|
|
if ret == 0 {
|
|
return "unknown"
|
|
}
|
|
|
|
gb := float64(ms.TotalPhys) / (1024 * 1024 * 1024)
|
|
if gb >= 1 {
|
|
return fmt.Sprintf("%.0f GB", gb)
|
|
}
|
|
mb := float64(ms.TotalPhys) / (1024 * 1024)
|
|
return fmt.Sprintf("%.0f MB", mb)
|
|
}
|
|
|
|
func HostArch() string {
|
|
if arch := os.Getenv("PROCESSOR_ARCHITEW6432"); arch != "" {
|
|
switch strings.ToLower(arch) {
|
|
case "amd64":
|
|
return "amd64"
|
|
case "arm64":
|
|
return "arm64"
|
|
}
|
|
}
|
|
if arch := os.Getenv("PROCESSOR_ARCHITECTURE"); arch != "" {
|
|
switch strings.ToLower(arch) {
|
|
case "amd64":
|
|
return "amd64"
|
|
case "arm64":
|
|
return "arm64"
|
|
case "x86":
|
|
return "386"
|
|
}
|
|
}
|
|
return runtime.GOARCH
|
|
}
|