//go:build windows // +build windows package comm import ( "context" "crypto/md5" "crypto/rand" "encoding/base64" "encoding/hex" "fmt" "net" "strings" "unsafe" "github.com/StackExchange/wmi" "golang.org/x/sys/windows" ) func GetPhysicalID() string { var ids []string mac := getMACAddress() if len(mac) < 1 { mac = "mac" } ids = append(ids, mac) guid, _ := getMachineGuid() if len(guid) < 1 { guid = "guid" } ids = append(ids, guid) cpuinfo, err := getCPUInfo() cpus := []string{} if err == nil { for _, c := range cpuinfo { cpus = append(cpus, c.VendorID+c.PhysicalID) } } cpu := "cpu" if len(cpu) > 0 { cpu = strings.Join(cpus, ",") } ids = append(ids, cpu) idsstr := strings.Join(ids, "|") return idsstr } func getMACAddress() string { netInterfaces, err := net.Interfaces() if err != nil { return "" } for i := 0; i < len(netInterfaces); i++ { //fmt.Println(netInterfaces[i]) if (netInterfaces[i].Flags&net.FlagUp) != 0 && (netInterfaces[i].Flags&net.FlagLoopback) == 0 { addrs, _ := netInterfaces[i].Addrs() for _, address := range addrs { ipnet, ok := address.(*net.IPNet) //fmt.Println(ipnet.IP) if ok && ipnet.IP.IsGlobalUnicast() { // 如果IP是全局单拨地址,则返回MAC地址 return netInterfaces[i].HardwareAddr.String() } } } } return "" } type cpuInfo struct { CPU int32 `json:"cpu"` VendorID string `json:"vendorId"` PhysicalID string `json:"physicalId"` } type win32_Processor struct { Manufacturer string ProcessorID *string } func getCPUInfo() ([]cpuInfo, error) { var ret []cpuInfo var dst []win32_Processor q := wmi.CreateQuery(&dst, "") fmt.Println(q) if err := wmiQuery(q, &dst); err != nil { return ret, err } var procID string for i, l := range dst { procID = "" if l.ProcessorID != nil { procID = *l.ProcessorID } cpu := cpuInfo{ CPU: int32(i), VendorID: l.Manufacturer, PhysicalID: procID, } ret = append(ret, cpu) } return ret, nil } // WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging func wmiQuery(query string, dst interface{}, connectServerArgs ...interface{}) error { ctx := context.Background() if _, ok := ctx.Deadline(); !ok { ctxTimeout, cancel := context.WithTimeout(ctx, 3000000000) //超时时间3s defer cancel() ctx = ctxTimeout } errChan := make(chan error, 1) go func() { errChan <- wmi.Query(query, dst, connectServerArgs...) }() select { case <-ctx.Done(): return ctx.Err() case err := <-errChan: return err } } func getMachineGuid() (string, error) { // there has been reports of issues on 32bit using golang.org/x/sys/windows/registry, see https://github.com/shirou/gopsutil/pull/312#issuecomment-277422612 // for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue var h windows.Handle err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h) if err != nil { return "", err } defer windows.RegCloseKey(h) const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16 const uuidLen = 36 var regBuf [windowsRegBufLen]uint16 bufLen := uint32(windowsRegBufLen) var valType uint32 err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err != nil { return "", err } hostID := windows.UTF16ToString(regBuf[:]) hostIDLen := len(hostID) if hostIDLen != uuidLen { return "", fmt.Errorf("HostID incorrect: %q\n", hostID) } return hostID, nil } // 生成32位md5字串 func GetMd5String(s string, upper bool, half bool) string { h := md5.New() h.Write([]byte(s)) result := hex.EncodeToString(h.Sum(nil)) if upper == true { result = strings.ToUpper(result) } if half == true { result = result[8:24] } return result } // 利用随机数生成Guid字串 func UniqueId() string { b := make([]byte, 48) if _, err := rand.Read(b); err != nil { return "" } return GetMd5String(base64.URLEncoding.EncodeToString(b), true, false) } func GetDeviceHash() string { //校验设备 id := GetPhysicalID() if len(id) < 1 { return "" } return GetMd5String(id, true, true) }