github.com/iDigitalFlame/xmt@v0.5.4/device/winapi/registry/value.go (about) 1 //go:build windows 2 // +build windows 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package registry 21 22 import ( 23 "syscall" 24 "unsafe" 25 26 "github.com/iDigitalFlame/xmt/device/winapi" 27 "github.com/iDigitalFlame/xmt/util" 28 ) 29 30 const ( 31 // ErrNotExist is returned when a registry key or value does not exist. 32 ErrNotExist = syscall.ERROR_FILE_NOT_FOUND 33 // ErrShortBuffer is returned when the buffer was too short for the operation. 34 ErrShortBuffer = syscall.ERROR_MORE_DATA 35 ) 36 37 // SetString sets the data and type of a named value under the key to the 38 // supplied value and SZ. 39 // 40 // The value must not contain a zero byte. 41 func (k Key) SetString(n, v string) error { 42 return k.setStringValue(n, TypeString, v) 43 } 44 45 // SetExpandString sets the data and type of a named value under the key 46 // to the supplied value and EXPAND_SZ. 47 // 48 // The value must not contain a zero byte. 49 func (k Key) SetExpandString(n, v string) error { 50 return k.setStringValue(n, TypeExpandString, v) 51 } 52 53 // SetDWord sets the data and type of a named value under the key to the 54 // supplied value and DWORD. 55 func (k Key) SetDWord(n string, v uint32) error { 56 return k.setValue(n, TypeDword, (*[4]byte)(unsafe.Pointer(&v))[:]) 57 } 58 59 // SetQWord sets the data and type of a named value under the key to the 60 // supplied value and QWORD. 61 func (k Key) SetQWord(n string, v uint64) error { 62 return k.setValue(n, TypeQword, (*[8]byte)(unsafe.Pointer(&v))[:]) 63 } 64 65 // SetBinary sets the data and type of a name value under key k to value and 66 // BINARY. 67 func (k Key) SetBinary(n string, v []byte) error { 68 return k.setValue(n, TypeBinary, v) 69 } 70 71 // SetStrings sets the data and type of a named value under the key to the 72 // supplied value and MULTI_SZ. 73 // 74 // The value strings must not contain a zero byte. 75 func (k Key) SetStrings(n string, v []string) error { 76 var b util.Builder 77 for i := range v { 78 for x := range v[i] { 79 if v[i][x] == 0 { 80 return syscall.EINVAL 81 } 82 } 83 b.WriteString(v[i] + "\x00") 84 } 85 var ( 86 r = winapi.UTF16EncodeStd([]rune(b.Output() + "\x00")) 87 o = (*[1 << 29]byte)(unsafe.Pointer(&r[0]))[: len(r)*2 : len(r)*2] 88 ) 89 return k.setValue(n, TypeStringList, o) 90 } 91 92 // String retrieves the string value for the specified value name 93 // associated with the open key. It also returns the value's type. 94 // 95 // If value does not exist, String returns ErrNotExist. 96 // 97 // If value is not SZ or EXPAND_SZ, it will return the correct value type and 98 // ErrUnexpectedType. 99 func (k Key) String(s string) (string, uint32, error) { 100 d, t, err := k.getValue(s, make([]byte, 64)) 101 if err != nil { 102 return "", t, err 103 } 104 switch t { 105 case TypeString, TypeExpandString: 106 default: 107 return "", t, ErrUnexpectedType 108 } 109 if len(d) == 0 { 110 return "", t, nil 111 } 112 u := (*[1 << 29]uint16)(unsafe.Pointer(&d[0]))[: len(d)/2 : len(d)/2] 113 return winapi.UTF16ToString(u), t, nil 114 } 115 116 // Binary retrieves the binary value for the specified value name 117 // associated with the open key. It also returns the value's type. 118 // 119 // If value does not exist, Binary returns ErrNotExist. 120 // 121 // If value is not BINARY, it will return the correct value type and 122 // ErrUnexpectedType. 123 func (k Key) Binary(s string) ([]byte, uint32, error) { 124 d, t, err := k.getValue(s, make([]byte, 64)) 125 if err != nil { 126 return nil, t, err 127 } 128 if t != TypeBinary { 129 return nil, t, ErrUnexpectedType 130 } 131 return d, t, nil 132 } 133 134 // Integer retrieves the integer value for the specified value name 135 // associated with the open key. It also returns the value's type. 136 // 137 // If value does not exist, Integer returns ErrNotExist. 138 // 139 // If value is not DWORD or QWORD, it will return the correct value type and 140 // ErrUnexpectedType. 141 func (k Key) Integer(s string) (uint64, uint32, error) { 142 d, t, err := k.getValue(s, make([]byte, 8)) 143 if err != nil { 144 return 0, t, err 145 } 146 switch t { 147 case TypeDword: 148 if len(d) != 4 { 149 return 0, t, ErrUnexpectedSize 150 } 151 _ = d[3] 152 return uint64(d[0]) | uint64(d[1])<<8 | uint64(d[2])<<16 | uint64(d[3])<<24, t, nil 153 case TypeQword: 154 if len(d) != 8 { 155 return 0, t, ErrUnexpectedSize 156 } 157 _ = d[7] 158 return uint64(d[0]) | uint64(d[1])<<8 | uint64(d[2])<<16 | uint64(d[3])<<24 | 159 uint64(d[4])<<32 | uint64(d[5])<<40 | uint64(d[6])<<48 | uint64(d[7])<<56, t, nil 160 default: 161 } 162 return 0, t, ErrUnexpectedType 163 } 164 165 // Strings retrieves the []string value for the specified value name 166 // associated with an open key k. It also returns the value's type. 167 // 168 // If value does not exist, Strings returns ErrNotExist. 169 // 170 // If value is not MULTI_SZ, it will return the correct value type and 171 // ErrUnexpectedType. 172 func (k Key) Strings(s string) ([]string, uint32, error) { 173 d, t, err := k.getValue(s, make([]byte, 64)) 174 if err != nil { 175 return nil, t, err 176 } 177 if t != TypeStringList { 178 return nil, t, ErrUnexpectedType 179 } 180 if len(d) == 0 { 181 return nil, t, nil 182 } 183 p := (*[1 << 29]uint16)(unsafe.Pointer(&d[0]))[: len(d)/2 : len(d)/2] 184 if len(p) == 0 { 185 return nil, t, nil 186 } 187 if p[len(p)-1] == 0 { 188 p = p[:len(p)-1] 189 } 190 r := make([]string, 0, 5) 191 for i, n := 0, 0; i < len(p); i++ { 192 if p[i] > 0 { 193 continue 194 } 195 r = append(r, string(winapi.UTF16Decode(p[n:i]))) 196 n = i + 1 197 } 198 return r, t, nil 199 } 200 func (k Key) setValue(s string, t uint32, d []byte) error { 201 if len(d) == 0 { 202 return winapi.RegSetValueEx(uintptr(k), s, t, nil, 0) 203 } 204 return winapi.RegSetValueEx(uintptr(k), s, t, &d[0], uint32(len(d))) 205 } 206 207 // Value retrieves the type and data for the specified value associated with 208 // the open key. 209 // 210 // It fills up buffer buf and returns the retrieved byte count n. If buf is too 211 // small to fit the stored value it returns an ErrShortBuffer error along with 212 // the required buffer size n. 213 // 214 // If no buffer is provided, it returns true and actual buffer size and the 215 // value's type only. 216 // 217 // If the value does not exist, the error returned is ErrNotExist. 218 // 219 // GetValue is a low level function. If value's type is known, use the 220 // appropriate "Value" function instead. 221 func (k Key) Value(s string, b []byte) (int, uint32, error) { 222 n, err := winapi.UTF16PtrFromString(s) 223 if err != nil { 224 return 0, 0, err 225 } 226 var ( 227 l = uint32(len(b)) 228 t uint32 229 o *byte 230 ) 231 if l > 0 { 232 o = (*byte)(&b[0]) 233 } 234 if err = syscall.RegQueryValueEx(syscall.Handle(k), n, nil, &t, o, &l); err != nil { 235 return int(l), t, err 236 } 237 return int(l), t, nil 238 } 239 func (k Key) setStringValue(n string, t uint32, v string) error { 240 p, err := winapi.UTF16FromString(v) 241 if err != nil { 242 return err 243 } 244 return k.setValue(n, t, (*[1 << 29]byte)(unsafe.Pointer(&p[0]))[:len(p)*2:len(p)*2]) 245 } 246 func (k Key) getValue(s string, b []byte) ([]byte, uint32, error) { 247 p, err := syscall.UTF16PtrFromString(s) 248 if err != nil { 249 return nil, 0, err 250 } 251 var ( 252 n = uint32(len(b)) 253 t uint32 254 ) 255 for { 256 err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(&b[0]), &n) 257 if err == nil { 258 return b[:n], t, nil 259 } 260 if err != syscall.ERROR_MORE_DATA { 261 return nil, 0, err 262 } 263 if n <= uint32(len(b)) { 264 return nil, 0, err 265 } 266 b = make([]byte, n) 267 } 268 }