| 267 | } |
| 268 | |
| 269 | std::string KeyHandler::ReadValue(cm::string_view name, |
| 270 | ValueTypeSet supportedTypes, |
| 271 | cm::string_view separator) |
| 272 | { |
| 273 | LSTATUS status; |
| 274 | DWORD size; |
| 275 | // pick-up maximum size for value |
| 276 | if ((status = RegQueryInfoKeyW(this->Handler, nullptr, nullptr, nullptr, |
| 277 | nullptr, nullptr, nullptr, nullptr, nullptr, |
| 278 | &size, nullptr, nullptr)) != ERROR_SUCCESS) { |
| 279 | throw registry_error(this->FormatSystemError(status)); |
| 280 | } |
| 281 | auto data = cm::make_unique<BYTE[]>(size); |
| 282 | DWORD type; |
| 283 | auto valueName = this->ToWide(name); |
| 284 | if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr, |
| 285 | &type, data.get(), &size)) != ERROR_SUCCESS) { |
| 286 | throw registry_error(this->FormatSystemError(status)); |
| 287 | } |
| 288 | |
| 289 | auto valueType = ToValueType(type); |
| 290 | if (!valueType || !supportedTypes.contains(*valueType)) { |
| 291 | throw registry_error(cmStrCat(type, ": unsupported type.")); |
| 292 | } |
| 293 | |
| 294 | switch (type) { |
| 295 | case REG_SZ: |
| 296 | return this->ToNarrow(reinterpret_cast<wchar_t*>(data.get())); |
| 297 | break; |
| 298 | case REG_EXPAND_SZ: { |
| 299 | auto expandSize = ExpandEnvironmentStringsW( |
| 300 | reinterpret_cast<wchar_t*>(data.get()), nullptr, 0); |
| 301 | auto expandData = cm::make_unique<wchar_t[]>(expandSize + 1); |
| 302 | if (ExpandEnvironmentStringsW(reinterpret_cast<wchar_t*>(data.get()), |
| 303 | expandData.get(), expandSize + 1) == 0) { |
| 304 | throw registry_error(this->FormatSystemError(GetLastError())); |
| 305 | } else { |
| 306 | return this->ToNarrow(expandData.get()); |
| 307 | } |
| 308 | } break; |
| 309 | case REG_DWORD: |
| 310 | return std::to_string(*reinterpret_cast<std::uint32_t*>(data.get())); |
| 311 | break; |
| 312 | case REG_QWORD: |
| 313 | return std::to_string(*reinterpret_cast<std::uint64_t*>(data.get())); |
| 314 | break; |
| 315 | case REG_MULTI_SZ: { |
| 316 | // replace separator with semicolon |
| 317 | auto sep = this->ToWide(separator)[0]; |
| 318 | std::replace(reinterpret_cast<wchar_t*>(data.get()), |
| 319 | reinterpret_cast<wchar_t*>(data.get()) + |
| 320 | (size / sizeof(wchar_t)) - 1, |
| 321 | sep, L';'); |
| 322 | return this->ToNarrow(reinterpret_cast<wchar_t*>(data.get())); |
| 323 | } break; |
| 324 | default: |
| 325 | throw registry_error(cmStrCat(type, ": unsupported type.")); |
| 326 | } |
no test coverage detected