github.com/SandwichDev/go-internals@v0.0.0-20210605002614-12311ac6b2c5/syscall/windows/registry/value.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build windows 6 7 package registry 8 9 import ( 10 "errors" 11 "syscall" 12 "unicode/utf16" 13 "unsafe" 14 ) 15 16 const ( 17 // Registry value types. 18 NONE = 0 19 SZ = 1 20 EXPAND_SZ = 2 21 BINARY = 3 22 DWORD = 4 23 DWORD_BIG_ENDIAN = 5 24 LINK = 6 25 MULTI_SZ = 7 26 RESOURCE_LIST = 8 27 FULL_RESOURCE_DESCRIPTOR = 9 28 RESOURCE_REQUIREMENTS_LIST = 10 29 QWORD = 11 30 ) 31 32 var ( 33 // ErrShortBuffer is returned when the buffer was too short for the operation. 34 ErrShortBuffer = syscall.ERROR_MORE_DATA 35 36 // ErrNotExist is returned when a registry key or value does not exist. 37 ErrNotExist = syscall.ERROR_FILE_NOT_FOUND 38 39 // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected. 40 ErrUnexpectedType = errors.New("unexpected key value type") 41 ) 42 43 // GetValue retrieves the type and data for the specified value associated 44 // with an open key k. It fills up buffer buf and returns the retrieved 45 // byte count n. If buf is too small to fit the stored value it returns 46 // ErrShortBuffer error along with the required buffer size n. 47 // If no buffer is provided, it returns true and actual buffer size n. 48 // If no buffer is provided, GetValue returns the value's type only. 49 // If the value does not exist, the error returned is ErrNotExist. 50 // 51 // GetValue is a low level function. If value's type is known, use the appropriate 52 // Get*Value function instead. 53 func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) { 54 pname, err := syscall.UTF16PtrFromString(name) 55 if err != nil { 56 return 0, 0, err 57 } 58 var pbuf *byte 59 if len(buf) > 0 { 60 pbuf = (*byte)(unsafe.Pointer(&buf[0])) 61 } 62 l := uint32(len(buf)) 63 err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l) 64 if err != nil { 65 return int(l), valtype, err 66 } 67 return int(l), valtype, nil 68 } 69 70 func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) { 71 p, err := syscall.UTF16PtrFromString(name) 72 if err != nil { 73 return nil, 0, err 74 } 75 var t uint32 76 n := uint32(len(buf)) 77 for { 78 err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n) 79 if err == nil { 80 return buf[:n], t, nil 81 } 82 if err != syscall.ERROR_MORE_DATA { 83 return nil, 0, err 84 } 85 if n <= uint32(len(buf)) { 86 return nil, 0, err 87 } 88 buf = make([]byte, n) 89 } 90 } 91 92 // GetStringValue retrieves the string value for the specified 93 // value name associated with an open key k. It also returns the value's type. 94 // If value does not exist, GetStringValue returns ErrNotExist. 95 // If value is not SZ or EXPAND_SZ, it will return the correct value 96 // type and ErrUnexpectedType. 97 func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) { 98 data, typ, err2 := k.getValue(name, make([]byte, 64)) 99 if err2 != nil { 100 return "", typ, err2 101 } 102 switch typ { 103 case SZ, EXPAND_SZ: 104 default: 105 return "", typ, ErrUnexpectedType 106 } 107 if len(data) == 0 { 108 return "", typ, nil 109 } 110 u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2] 111 return syscall.UTF16ToString(u), typ, nil 112 } 113 114 // GetMUIStringValue retrieves the localized string value for 115 // the specified value name associated with an open key k. 116 // If the value name doesn't exist or the localized string value 117 // can't be resolved, GetMUIStringValue returns ErrNotExist. 118 // GetMUIStringValue panics if the system doesn't support 119 // regLoadMUIString; use LoadRegLoadMUIString to check if 120 // regLoadMUIString is supported before calling this function. 121 func (k Key) GetMUIStringValue(name string) (string, error) { 122 pname, err := syscall.UTF16PtrFromString(name) 123 if err != nil { 124 return "", err 125 } 126 127 buf := make([]uint16, 1024) 128 var buflen uint32 129 var pdir *uint16 130 131 err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) 132 if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path 133 134 // Try to resolve the string value using the system directory as 135 // a DLL search path; this assumes the string value is of the form 136 // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320. 137 138 // This approach works with tzres.dll but may have to be revised 139 // in the future to allow callers to provide custom search paths. 140 141 var s string 142 s, err = ExpandString("%SystemRoot%\\system32\\") 143 if err != nil { 144 return "", err 145 } 146 pdir, err = syscall.UTF16PtrFromString(s) 147 if err != nil { 148 return "", err 149 } 150 151 err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) 152 } 153 154 for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed 155 if buflen <= uint32(len(buf)) { 156 break // Buffer not growing, assume race; break 157 } 158 buf = make([]uint16, buflen) 159 err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) 160 } 161 162 if err != nil { 163 return "", err 164 } 165 166 return syscall.UTF16ToString(buf), nil 167 } 168 169 // ExpandString expands environment-variable strings and replaces 170 // them with the values defined for the current user. 171 // Use ExpandString to expand EXPAND_SZ strings. 172 func ExpandString(value string) (string, error) { 173 if value == "" { 174 return "", nil 175 } 176 p, err := syscall.UTF16PtrFromString(value) 177 if err != nil { 178 return "", err 179 } 180 r := make([]uint16, 100) 181 for { 182 n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r))) 183 if err != nil { 184 return "", err 185 } 186 if n <= uint32(len(r)) { 187 return syscall.UTF16ToString(r[:n]), nil 188 } 189 r = make([]uint16, n) 190 } 191 } 192 193 // GetStringsValue retrieves the []string value for the specified 194 // value name associated with an open key k. It also returns the value's type. 195 // If value does not exist, GetStringsValue returns ErrNotExist. 196 // If value is not MULTI_SZ, it will return the correct value 197 // type and ErrUnexpectedType. 198 func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) { 199 data, typ, err2 := k.getValue(name, make([]byte, 64)) 200 if err2 != nil { 201 return nil, typ, err2 202 } 203 if typ != MULTI_SZ { 204 return nil, typ, ErrUnexpectedType 205 } 206 if len(data) == 0 { 207 return nil, typ, nil 208 } 209 p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2] 210 if len(p) == 0 { 211 return nil, typ, nil 212 } 213 if p[len(p)-1] == 0 { 214 p = p[:len(p)-1] // remove terminating null 215 } 216 val = make([]string, 0, 5) 217 from := 0 218 for i, c := range p { 219 if c == 0 { 220 val = append(val, string(utf16.Decode(p[from:i]))) 221 from = i + 1 222 } 223 } 224 return val, typ, nil 225 } 226 227 // GetIntegerValue retrieves the integer value for the specified 228 // value name associated with an open key k. It also returns the value's type. 229 // If value does not exist, GetIntegerValue returns ErrNotExist. 230 // If value is not DWORD or QWORD, it will return the correct value 231 // type and ErrUnexpectedType. 232 func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) { 233 data, typ, err2 := k.getValue(name, make([]byte, 8)) 234 if err2 != nil { 235 return 0, typ, err2 236 } 237 switch typ { 238 case DWORD: 239 if len(data) != 4 { 240 return 0, typ, errors.New("DWORD value is not 4 bytes long") 241 } 242 return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil 243 case QWORD: 244 if len(data) != 8 { 245 return 0, typ, errors.New("QWORD value is not 8 bytes long") 246 } 247 return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil 248 default: 249 return 0, typ, ErrUnexpectedType 250 } 251 } 252 253 // GetBinaryValue retrieves the binary value for the specified 254 // value name associated with an open key k. It also returns the value's type. 255 // If value does not exist, GetBinaryValue returns ErrNotExist. 256 // If value is not BINARY, it will return the correct value 257 // type and ErrUnexpectedType. 258 func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) { 259 data, typ, err2 := k.getValue(name, make([]byte, 64)) 260 if err2 != nil { 261 return nil, typ, err2 262 } 263 if typ != BINARY { 264 return nil, typ, ErrUnexpectedType 265 } 266 return data, typ, nil 267 } 268 269 func (k Key) setValue(name string, valtype uint32, data []byte) error { 270 p, err := syscall.UTF16PtrFromString(name) 271 if err != nil { 272 return err 273 } 274 if len(data) == 0 { 275 return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0) 276 } 277 return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data))) 278 } 279 280 // SetDWordValue sets the data and type of a name value 281 // under key k to value and DWORD. 282 func (k Key) SetDWordValue(name string, value uint32) error { 283 return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:]) 284 } 285 286 // SetQWordValue sets the data and type of a name value 287 // under key k to value and QWORD. 288 func (k Key) SetQWordValue(name string, value uint64) error { 289 return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:]) 290 } 291 292 func (k Key) setStringValue(name string, valtype uint32, value string) error { 293 v, err := syscall.UTF16FromString(value) 294 if err != nil { 295 return err 296 } 297 buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2] 298 return k.setValue(name, valtype, buf) 299 } 300 301 // SetStringValue sets the data and type of a name value 302 // under key k to value and SZ. The value must not contain a zero byte. 303 func (k Key) SetStringValue(name, value string) error { 304 return k.setStringValue(name, SZ, value) 305 } 306 307 // SetExpandStringValue sets the data and type of a name value 308 // under key k to value and EXPAND_SZ. The value must not contain a zero byte. 309 func (k Key) SetExpandStringValue(name, value string) error { 310 return k.setStringValue(name, EXPAND_SZ, value) 311 } 312 313 // SetStringsValue sets the data and type of a name value 314 // under key k to value and MULTI_SZ. The value strings 315 // must not contain a zero byte. 316 func (k Key) SetStringsValue(name string, value []string) error { 317 ss := "" 318 for _, s := range value { 319 for i := 0; i < len(s); i++ { 320 if s[i] == 0 { 321 return errors.New("string cannot have 0 inside") 322 } 323 } 324 ss += s + "\x00" 325 } 326 v := utf16.Encode([]rune(ss + "\x00")) 327 buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2] 328 return k.setValue(name, MULTI_SZ, buf) 329 } 330 331 // SetBinaryValue sets the data and type of a name value 332 // under key k to value and BINARY. 333 func (k Key) SetBinaryValue(name string, value []byte) error { 334 return k.setValue(name, BINARY, value) 335 } 336 337 // DeleteValue removes a named value from the key k. 338 func (k Key) DeleteValue(name string) error { 339 return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) 340 } 341 342 // ReadValueNames returns the value names of key k. 343 func (k Key) ReadValueNames() ([]string, error) { 344 ki, err := k.Stat() 345 if err != nil { 346 return nil, err 347 } 348 names := make([]string, 0, ki.ValueCount) 349 buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character 350 loopItems: 351 for i := uint32(0); ; i++ { 352 l := uint32(len(buf)) 353 for { 354 err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) 355 if err == nil { 356 break 357 } 358 if err == syscall.ERROR_MORE_DATA { 359 // Double buffer size and try again. 360 l = uint32(2 * len(buf)) 361 buf = make([]uint16, l) 362 continue 363 } 364 if err == _ERROR_NO_MORE_ITEMS { 365 break loopItems 366 } 367 return names, err 368 } 369 names = append(names, syscall.UTF16ToString(buf[:l])) 370 } 371 return names, nil 372 }