value.mx raw

   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  //go: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  func (k Key) GetMUIStringValue(name string) (string, error) {
 119  	pname, err := syscall.UTF16PtrFromString(name)
 120  	if err != nil {
 121  		return "", err
 122  	}
 123  
 124  	buf := make([]uint16, 1024)
 125  	var buflen uint32
 126  	var pdir *uint16
 127  
 128  	err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
 129  	if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
 130  
 131  		// Try to resolve the string value using the system directory as
 132  		// a DLL search path; this assumes the string value is of the form
 133  		// @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
 134  
 135  		// This approach works with tzres.dll but may have to be revised
 136  		// in the future to allow callers to provide custom search paths.
 137  
 138  		var s string
 139  		s, err = ExpandString("%SystemRoot%\\system32\\")
 140  		if err != nil {
 141  			return "", err
 142  		}
 143  		pdir, err = syscall.UTF16PtrFromString(s)
 144  		if err != nil {
 145  			return "", err
 146  		}
 147  
 148  		err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
 149  	}
 150  
 151  	for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
 152  		if buflen <= uint32(len(buf)) {
 153  			break // Buffer not growing, assume race; break
 154  		}
 155  		buf = make([]uint16, buflen)
 156  		err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
 157  	}
 158  
 159  	if err != nil {
 160  		return "", err
 161  	}
 162  
 163  	return syscall.UTF16ToString(buf), nil
 164  }
 165  
 166  // ExpandString expands environment-variable strings and replaces
 167  // them with the values defined for the current user.
 168  // Use ExpandString to expand EXPAND_SZ strings.
 169  func ExpandString(value string) (string, error) {
 170  	if value == "" {
 171  		return "", nil
 172  	}
 173  	p, err := syscall.UTF16PtrFromString(value)
 174  	if err != nil {
 175  		return "", err
 176  	}
 177  	r := make([]uint16, 100)
 178  	for {
 179  		n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
 180  		if err != nil {
 181  			return "", err
 182  		}
 183  		if n <= uint32(len(r)) {
 184  			return syscall.UTF16ToString(r[:n]), nil
 185  		}
 186  		r = make([]uint16, n)
 187  	}
 188  }
 189  
 190  // GetStringsValue retrieves the []string value for the specified
 191  // value name associated with an open key k. It also returns the value's type.
 192  // If value does not exist, GetStringsValue returns ErrNotExist.
 193  // If value is not MULTI_SZ, it will return the correct value
 194  // type and ErrUnexpectedType.
 195  func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
 196  	data, typ, err2 := k.getValue(name, make([]byte, 64))
 197  	if err2 != nil {
 198  		return nil, typ, err2
 199  	}
 200  	if typ != MULTI_SZ {
 201  		return nil, typ, ErrUnexpectedType
 202  	}
 203  	if len(data) == 0 {
 204  		return nil, typ, nil
 205  	}
 206  	p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2]
 207  	if len(p) == 0 {
 208  		return nil, typ, nil
 209  	}
 210  	if p[len(p)-1] == 0 {
 211  		p = p[:len(p)-1] // remove terminating null
 212  	}
 213  	val = make([]string, 0, 5)
 214  	from := 0
 215  	for i, c := range p {
 216  		if c == 0 {
 217  			val = append(val, syscall.UTF16ToString(p[from:i]))
 218  			from = i + 1
 219  		}
 220  	}
 221  	return val, typ, nil
 222  }
 223  
 224  // GetIntegerValue retrieves the integer value for the specified
 225  // value name associated with an open key k. It also returns the value's type.
 226  // If value does not exist, GetIntegerValue returns ErrNotExist.
 227  // If value is not DWORD or QWORD, it will return the correct value
 228  // type and ErrUnexpectedType.
 229  func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
 230  	data, typ, err2 := k.getValue(name, make([]byte, 8))
 231  	if err2 != nil {
 232  		return 0, typ, err2
 233  	}
 234  	switch typ {
 235  	case DWORD:
 236  		if len(data) != 4 {
 237  			return 0, typ, errors.New("DWORD value is not 4 bytes long")
 238  		}
 239  		return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
 240  	case QWORD:
 241  		if len(data) != 8 {
 242  			return 0, typ, errors.New("QWORD value is not 8 bytes long")
 243  		}
 244  		return *(*uint64)(unsafe.Pointer(&data[0])), QWORD, nil
 245  	default:
 246  		return 0, typ, ErrUnexpectedType
 247  	}
 248  }
 249  
 250  // GetBinaryValue retrieves the binary value for the specified
 251  // value name associated with an open key k. It also returns the value's type.
 252  // If value does not exist, GetBinaryValue returns ErrNotExist.
 253  // If value is not BINARY, it will return the correct value
 254  // type and ErrUnexpectedType.
 255  func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
 256  	data, typ, err2 := k.getValue(name, make([]byte, 64))
 257  	if err2 != nil {
 258  		return nil, typ, err2
 259  	}
 260  	if typ != BINARY {
 261  		return nil, typ, ErrUnexpectedType
 262  	}
 263  	return data, typ, nil
 264  }
 265  
 266  func (k Key) setValue(name string, valtype uint32, data []byte) error {
 267  	p, err := syscall.UTF16PtrFromString(name)
 268  	if err != nil {
 269  		return err
 270  	}
 271  	if len(data) == 0 {
 272  		return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
 273  	}
 274  	return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
 275  }
 276  
 277  // SetDWordValue sets the data and type of a name value
 278  // under key k to value and DWORD.
 279  func (k Key) SetDWordValue(name string, value uint32) error {
 280  	return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
 281  }
 282  
 283  // SetQWordValue sets the data and type of a name value
 284  // under key k to value and QWORD.
 285  func (k Key) SetQWordValue(name string, value uint64) error {
 286  	return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
 287  }
 288  
 289  func (k Key) setStringValue(name string, valtype uint32, value string) error {
 290  	v, err := syscall.UTF16FromString(value)
 291  	if err != nil {
 292  		return err
 293  	}
 294  	buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2]
 295  	return k.setValue(name, valtype, buf)
 296  }
 297  
 298  // SetStringValue sets the data and type of a name value
 299  // under key k to value and SZ. The value must not contain a zero byte.
 300  func (k Key) SetStringValue(name, value string) error {
 301  	return k.setStringValue(name, SZ, value)
 302  }
 303  
 304  // SetExpandStringValue sets the data and type of a name value
 305  // under key k to value and EXPAND_SZ. The value must not contain a zero byte.
 306  func (k Key) SetExpandStringValue(name, value string) error {
 307  	return k.setStringValue(name, EXPAND_SZ, value)
 308  }
 309  
 310  // SetStringsValue sets the data and type of a name value
 311  // under key k to value and MULTI_SZ. The value strings
 312  // must not contain a zero byte.
 313  func (k Key) SetStringsValue(name string, value []string) error {
 314  	ss := ""
 315  	for _, s := range value {
 316  		for i := 0; i < len(s); i++ {
 317  			if s[i] == 0 {
 318  				return errors.New("string cannot have 0 inside")
 319  			}
 320  		}
 321  		ss += s + "\x00"
 322  	}
 323  	v := utf16.Encode([]rune(ss + "\x00"))
 324  	buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2]
 325  	return k.setValue(name, MULTI_SZ, buf)
 326  }
 327  
 328  // SetBinaryValue sets the data and type of a name value
 329  // under key k to value and BINARY.
 330  func (k Key) SetBinaryValue(name string, value []byte) error {
 331  	return k.setValue(name, BINARY, value)
 332  }
 333  
 334  // DeleteValue removes a named value from the key k.
 335  func (k Key) DeleteValue(name string) error {
 336  	return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
 337  }
 338  
 339  // ReadValueNames returns the value names of key k.
 340  func (k Key) ReadValueNames() ([]string, error) {
 341  	ki, err := k.Stat()
 342  	if err != nil {
 343  		return nil, err
 344  	}
 345  	names := make([]string, 0, ki.ValueCount)
 346  	buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
 347  loopItems:
 348  	for i := uint32(0); ; i++ {
 349  		l := uint32(len(buf))
 350  		for {
 351  			err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
 352  			if err == nil {
 353  				break
 354  			}
 355  			if err == syscall.ERROR_MORE_DATA {
 356  				// Double buffer size and try again.
 357  				l = uint32(2 * len(buf))
 358  				buf = make([]uint16, l)
 359  				continue
 360  			}
 361  			if err == _ERROR_NO_MORE_ITEMS {
 362  				break loopItems
 363  			}
 364  			return names, err
 365  		}
 366  		names = append(names, syscall.UTF16ToString(buf[:l]))
 367  	}
 368  	return names, nil
 369  }
 370