blob: 447086aff5fcfffcaf544ec513004490a48e1204 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2003 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11// Registry configuration wrapers class implementation
12//
13// Change made by S. Ganesh - ganesh@google.com:
14// Use SHQueryValueEx instead of RegQueryValueEx throughout.
15// A call to the SHLWAPI function is essentially a call to the standard
16// function but with post-processing:
17// * to fix REG_SZ or REG_EXPAND_SZ data that is not properly null-terminated;
18// * to expand REG_EXPAND_SZ data.
19
20#include "webrtc/base/win32regkey.h"
21
22#include <shlwapi.h>
23
jbauch555604a2016-04-26 03:13:22 -070024#include <memory>
25
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026#include "webrtc/base/common.h"
27#include "webrtc/base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000028
29namespace rtc {
30
31RegKey::RegKey() {
32 h_key_ = NULL;
33}
34
35RegKey::~RegKey() {
36 Close();
37}
38
39HRESULT RegKey::Create(HKEY parent_key, const wchar_t* key_name) {
40 return Create(parent_key,
41 key_name,
42 REG_NONE,
43 REG_OPTION_NON_VOLATILE,
44 KEY_ALL_ACCESS,
45 NULL,
46 NULL);
47}
48
49HRESULT RegKey::Open(HKEY parent_key, const wchar_t* key_name) {
50 return Open(parent_key, key_name, KEY_ALL_ACCESS);
51}
52
53bool RegKey::HasValue(const TCHAR* value_name) const {
54 return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_, value_name, NULL,
55 NULL, NULL, NULL));
56}
57
58HRESULT RegKey::SetValue(const wchar_t* full_key_name,
59 const wchar_t* value_name,
60 DWORD value) {
61 ASSERT(full_key_name != NULL);
62
63 return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);
64}
65
66HRESULT RegKey::SetValue(const wchar_t* full_key_name,
67 const wchar_t* value_name,
68 DWORD64 value) {
69 ASSERT(full_key_name != NULL);
70
71 return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);
72}
73
74HRESULT RegKey::SetValue(const wchar_t* full_key_name,
75 const wchar_t* value_name,
76 float value) {
77 ASSERT(full_key_name != NULL);
78
79 return SetValueStaticHelper(full_key_name, value_name,
80 REG_BINARY, &value, sizeof(value));
81}
82
83HRESULT RegKey::SetValue(const wchar_t* full_key_name,
84 const wchar_t* value_name,
85 double value) {
86 ASSERT(full_key_name != NULL);
87
88 return SetValueStaticHelper(full_key_name, value_name,
89 REG_BINARY, &value, sizeof(value));
90}
91
92HRESULT RegKey::SetValue(const wchar_t* full_key_name,
93 const wchar_t* value_name,
94 const TCHAR* value) {
95 ASSERT(full_key_name != NULL);
96 ASSERT(value != NULL);
97
98 return SetValueStaticHelper(full_key_name, value_name,
99 REG_SZ, const_cast<wchar_t*>(value));
100}
101
102HRESULT RegKey::SetValue(const wchar_t* full_key_name,
103 const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200104 const uint8_t* value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105 DWORD byte_count) {
106 ASSERT(full_key_name != NULL);
107
108 return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200109 const_cast<uint8_t*>(value), byte_count);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000110}
111
112HRESULT RegKey::SetValueMultiSZ(const wchar_t* full_key_name,
113 const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200114 const uint8_t* value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000115 DWORD byte_count) {
116 ASSERT(full_key_name != NULL);
117
118 return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200119 const_cast<uint8_t*>(value), byte_count);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000120}
121
122HRESULT RegKey::GetValue(const wchar_t* full_key_name,
123 const wchar_t* value_name,
124 DWORD* value) {
125 ASSERT(full_key_name != NULL);
126 ASSERT(value != NULL);
127
128 return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);
129}
130
131HRESULT RegKey::GetValue(const wchar_t* full_key_name,
132 const wchar_t* value_name,
133 DWORD64* value) {
134 ASSERT(full_key_name != NULL);
135 ASSERT(value != NULL);
136
137 return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);
138}
139
140HRESULT RegKey::GetValue(const wchar_t* full_key_name,
141 const wchar_t* value_name,
142 float* value) {
143 ASSERT(value != NULL);
144 ASSERT(full_key_name != NULL);
145
146 DWORD byte_count = 0;
kwiberg345807e2016-03-29 10:16:34 -0700147 byte* buffer_raw = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
kwiberg345807e2016-03-29 10:16:34 -0700149 REG_BINARY, &buffer_raw, &byte_count);
jbauch555604a2016-04-26 03:13:22 -0700150 std::unique_ptr<byte[]> buffer(buffer_raw);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151 if (SUCCEEDED(hr)) {
152 ASSERT(byte_count == sizeof(*value));
153 if (byte_count == sizeof(*value)) {
154 *value = *reinterpret_cast<float*>(buffer.get());
155 }
156 }
157 return hr;
158}
159
160HRESULT RegKey::GetValue(const wchar_t* full_key_name,
161 const wchar_t* value_name,
162 double* value) {
163 ASSERT(value != NULL);
164 ASSERT(full_key_name != NULL);
165
166 DWORD byte_count = 0;
kwiberg345807e2016-03-29 10:16:34 -0700167 byte* buffer_raw = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000168 HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
kwiberg345807e2016-03-29 10:16:34 -0700169 REG_BINARY, &buffer_raw, &byte_count);
jbauch555604a2016-04-26 03:13:22 -0700170 std::unique_ptr<byte[]> buffer(buffer_raw);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000171 if (SUCCEEDED(hr)) {
172 ASSERT(byte_count == sizeof(*value));
173 if (byte_count == sizeof(*value)) {
174 *value = *reinterpret_cast<double*>(buffer.get());
175 }
176 }
177 return hr;
178}
179
180HRESULT RegKey::GetValue(const wchar_t* full_key_name,
181 const wchar_t* value_name,
182 wchar_t** value) {
183 ASSERT(full_key_name != NULL);
184 ASSERT(value != NULL);
185
186 return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);
187}
188
189HRESULT RegKey::GetValue(const wchar_t* full_key_name,
190 const wchar_t* value_name,
191 std::wstring* value) {
192 ASSERT(full_key_name != NULL);
193 ASSERT(value != NULL);
194
kwiberg345807e2016-03-29 10:16:34 -0700195 wchar_t* buffer_raw = nullptr;
196 HRESULT hr = RegKey::GetValue(full_key_name, value_name, &buffer_raw);
jbauch555604a2016-04-26 03:13:22 -0700197 std::unique_ptr<wchar_t[]> buffer(buffer_raw);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198 if (SUCCEEDED(hr)) {
199 value->assign(buffer.get());
200 }
201 return hr;
202}
203
204HRESULT RegKey::GetValue(const wchar_t* full_key_name,
205 const wchar_t* value_name,
206 std::vector<std::wstring>* value) {
207 ASSERT(full_key_name != NULL);
208 ASSERT(value != NULL);
209
210 return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);
211}
212
213HRESULT RegKey::GetValue(const wchar_t* full_key_name,
214 const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200215 uint8_t** value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000216 DWORD* byte_count) {
217 ASSERT(full_key_name != NULL);
218 ASSERT(value != NULL);
219 ASSERT(byte_count != NULL);
220
221 return GetValueStaticHelper(full_key_name, value_name,
222 REG_BINARY, value, byte_count);
223}
224
225HRESULT RegKey::DeleteSubKey(const wchar_t* key_name) {
226 ASSERT(key_name != NULL);
227 ASSERT(h_key_ != NULL);
228
229 LONG res = ::RegDeleteKey(h_key_, key_name);
230 HRESULT hr = HRESULT_FROM_WIN32(res);
231 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
232 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
233 hr = S_FALSE;
234 }
235 return hr;
236}
237
238HRESULT RegKey::DeleteValue(const wchar_t* value_name) {
239 ASSERT(h_key_ != NULL);
240
241 LONG res = ::RegDeleteValue(h_key_, value_name);
242 HRESULT hr = HRESULT_FROM_WIN32(res);
243 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
244 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
245 hr = S_FALSE;
246 }
247 return hr;
248}
249
250HRESULT RegKey::Close() {
251 HRESULT hr = S_OK;
252 if (h_key_ != NULL) {
253 LONG res = ::RegCloseKey(h_key_);
254 hr = HRESULT_FROM_WIN32(res);
255 h_key_ = NULL;
256 }
257 return hr;
258}
259
260HRESULT RegKey::Create(HKEY parent_key,
261 const wchar_t* key_name,
262 wchar_t* lpszClass,
263 DWORD options,
264 REGSAM sam_desired,
265 LPSECURITY_ATTRIBUTES lpSecAttr,
266 LPDWORD lpdwDisposition) {
267 ASSERT(key_name != NULL);
268 ASSERT(parent_key != NULL);
269
270 DWORD dw = 0;
271 HKEY h_key = NULL;
272 LONG res = ::RegCreateKeyEx(parent_key, key_name, 0, lpszClass, options,
273 sam_desired, lpSecAttr, &h_key, &dw);
274 HRESULT hr = HRESULT_FROM_WIN32(res);
275
276 if (lpdwDisposition) {
277 *lpdwDisposition = dw;
278 }
279
280 // we have to close the currently opened key
281 // before replacing it with the new one
282 if (hr == S_OK) {
283 hr = Close();
284 ASSERT(hr == S_OK);
285 h_key_ = h_key;
286 }
287 return hr;
288}
289
290HRESULT RegKey::Open(HKEY parent_key,
291 const wchar_t* key_name,
292 REGSAM sam_desired) {
293 ASSERT(key_name != NULL);
294 ASSERT(parent_key != NULL);
295
296 HKEY h_key = NULL;
297 LONG res = ::RegOpenKeyEx(parent_key, key_name, 0, sam_desired, &h_key);
298 HRESULT hr = HRESULT_FROM_WIN32(res);
299
300 // we have to close the currently opened key
301 // before replacing it with the new one
302 if (hr == S_OK) {
303 // close the currently opened key if any
304 hr = Close();
305 ASSERT(hr == S_OK);
306 h_key_ = h_key;
307 }
308 return hr;
309}
310
311// save the key and all of its subkeys and values to a file
312HRESULT RegKey::Save(const wchar_t* full_key_name, const wchar_t* file_name) {
313 ASSERT(full_key_name != NULL);
314 ASSERT(file_name != NULL);
315
316 std::wstring key_name(full_key_name);
317 HKEY h_key = GetRootKeyInfo(&key_name);
318 if (!h_key) {
319 return E_FAIL;
320 }
321
322 RegKey key;
323 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
324 if (FAILED(hr)) {
325 return hr;
326 }
327
328 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, true);
329 LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);
330 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, false);
331
332 return HRESULT_FROM_WIN32(res);
333}
334
335// restore the key and all of its subkeys and values which are saved into a file
336HRESULT RegKey::Restore(const wchar_t* full_key_name,
337 const wchar_t* file_name) {
338 ASSERT(full_key_name != NULL);
339 ASSERT(file_name != NULL);
340
341 std::wstring key_name(full_key_name);
342 HKEY h_key = GetRootKeyInfo(&key_name);
343 if (!h_key) {
344 return E_FAIL;
345 }
346
347 RegKey key;
348 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_WRITE);
349 if (FAILED(hr)) {
350 return hr;
351 }
352
353 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, true);
354 LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);
355 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, false);
356
357 return HRESULT_FROM_WIN32(res);
358}
359
360// check if the current key has the specified subkey
361bool RegKey::HasSubkey(const wchar_t* key_name) const {
362 ASSERT(key_name != NULL);
363
364 RegKey key;
365 HRESULT hr = key.Open(h_key_, key_name, KEY_READ);
366 key.Close();
367 return hr == S_OK;
368}
369
370// static flush key
371HRESULT RegKey::FlushKey(const wchar_t* full_key_name) {
372 ASSERT(full_key_name != NULL);
373
374 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
375 // get the root HKEY
376 std::wstring key_name(full_key_name);
377 HKEY h_key = GetRootKeyInfo(&key_name);
378
379 if (h_key != NULL) {
380 LONG res = ::RegFlushKey(h_key);
381 hr = HRESULT_FROM_WIN32(res);
382 }
383 return hr;
384}
385
386// static SET helper
387HRESULT RegKey::SetValueStaticHelper(const wchar_t* full_key_name,
388 const wchar_t* value_name,
389 DWORD type,
390 LPVOID value,
391 DWORD byte_count) {
392 ASSERT(full_key_name != NULL);
393
394 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
395 // get the root HKEY
396 std::wstring key_name(full_key_name);
397 HKEY h_key = GetRootKeyInfo(&key_name);
398
399 if (h_key != NULL) {
400 RegKey key;
401 hr = key.Create(h_key, key_name.c_str());
402 if (hr == S_OK) {
403 switch (type) {
404 case REG_DWORD:
405 hr = key.SetValue(value_name, *(static_cast<DWORD*>(value)));
406 break;
407 case REG_QWORD:
408 hr = key.SetValue(value_name, *(static_cast<DWORD64*>(value)));
409 break;
410 case REG_SZ:
411 hr = key.SetValue(value_name, static_cast<const wchar_t*>(value));
412 break;
413 case REG_BINARY:
Peter Boström0c4e06b2015-10-07 12:23:21 +0200414 hr = key.SetValue(value_name, static_cast<const uint8_t*>(value),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000415 byte_count);
416 break;
417 case REG_MULTI_SZ:
Peter Boström0c4e06b2015-10-07 12:23:21 +0200418 hr = key.SetValue(value_name, static_cast<const uint8_t*>(value),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000419 byte_count, type);
420 break;
421 default:
422 ASSERT(false);
423 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
424 break;
425 }
426 // close the key after writing
427 HRESULT temp_hr = key.Close();
428 if (hr == S_OK) {
429 hr = temp_hr;
430 }
431 }
432 }
433 return hr;
434}
435
436// static GET helper
437HRESULT RegKey::GetValueStaticHelper(const wchar_t* full_key_name,
438 const wchar_t* value_name,
439 DWORD type,
440 LPVOID value,
441 DWORD* byte_count) {
442 ASSERT(full_key_name != NULL);
443
444 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
445 // get the root HKEY
446 std::wstring key_name(full_key_name);
447 HKEY h_key = GetRootKeyInfo(&key_name);
448
449 if (h_key != NULL) {
450 RegKey key;
451 hr = key.Open(h_key, key_name.c_str(), KEY_READ);
452 if (hr == S_OK) {
453 switch (type) {
454 case REG_DWORD:
455 hr = key.GetValue(value_name, reinterpret_cast<DWORD*>(value));
456 break;
457 case REG_QWORD:
458 hr = key.GetValue(value_name, reinterpret_cast<DWORD64*>(value));
459 break;
460 case REG_SZ:
461 hr = key.GetValue(value_name, reinterpret_cast<wchar_t**>(value));
462 break;
463 case REG_MULTI_SZ:
464 hr = key.GetValue(value_name, reinterpret_cast<
465 std::vector<std::wstring>*>(value));
466 break;
467 case REG_BINARY:
Peter Boström0c4e06b2015-10-07 12:23:21 +0200468 hr = key.GetValue(value_name, reinterpret_cast<uint8_t**>(value),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000469 byte_count);
470 break;
471 default:
472 ASSERT(false);
473 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
474 break;
475 }
476 // close the key after writing
477 HRESULT temp_hr = key.Close();
478 if (hr == S_OK) {
479 hr = temp_hr;
480 }
481 }
482 }
483 return hr;
484}
485
486// GET helper
487HRESULT RegKey::GetValueHelper(const wchar_t* value_name,
488 DWORD* type,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200489 uint8_t** value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000490 DWORD* byte_count) const {
491 ASSERT(byte_count != NULL);
492 ASSERT(value != NULL);
493 ASSERT(type != NULL);
494
495 // init return buffer
496 *value = NULL;
497
498 // get the size of the return data buffer
499 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count);
500 HRESULT hr = HRESULT_FROM_WIN32(res);
501
502 if (hr == S_OK) {
503 // if the value length is 0, nothing to do
504 if (*byte_count != 0) {
505 // allocate the buffer
506 *value = new byte[*byte_count];
507 ASSERT(*value != NULL);
508
509 // make the call again to get the data
510 res = ::SHQueryValueEx(h_key_, value_name, NULL,
511 type, *value, byte_count);
512 hr = HRESULT_FROM_WIN32(res);
513 ASSERT(hr == S_OK);
514 }
515 }
516 return hr;
517}
518
519// Int32 Get
520HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD* value) const {
521 ASSERT(value != NULL);
522
523 DWORD type = 0;
524 DWORD byte_count = sizeof(DWORD);
525 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
526 value, &byte_count);
527 HRESULT hr = HRESULT_FROM_WIN32(res);
528 ASSERT((hr != S_OK) || (type == REG_DWORD));
529 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD)));
530 return hr;
531}
532
533// Int64 Get
534HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD64* value) const {
535 ASSERT(value != NULL);
536
537 DWORD type = 0;
538 DWORD byte_count = sizeof(DWORD64);
539 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
540 value, &byte_count);
541 HRESULT hr = HRESULT_FROM_WIN32(res);
542 ASSERT((hr != S_OK) || (type == REG_QWORD));
543 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD64)));
544 return hr;
545}
546
547// String Get
548HRESULT RegKey::GetValue(const wchar_t* value_name, wchar_t** value) const {
549 ASSERT(value != NULL);
550
551 DWORD byte_count = 0;
552 DWORD type = 0;
553
554 // first get the size of the string buffer
555 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL,
556 &type, NULL, &byte_count);
557 HRESULT hr = HRESULT_FROM_WIN32(res);
558
559 if (hr == S_OK) {
560 // allocate room for the string and a terminating \0
561 *value = new wchar_t[(byte_count / sizeof(wchar_t)) + 1];
562
563 if ((*value) != NULL) {
564 if (byte_count != 0) {
565 // make the call again
566 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
567 *value, &byte_count);
568 hr = HRESULT_FROM_WIN32(res);
569 } else {
570 (*value)[0] = L'\0';
571 }
572
573 ASSERT((hr != S_OK) || (type == REG_SZ) ||
574 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
575 } else {
576 hr = E_OUTOFMEMORY;
577 }
578 }
579
580 return hr;
581}
582
583// get a string value
584HRESULT RegKey::GetValue(const wchar_t* value_name, std::wstring* value) const {
585 ASSERT(value != NULL);
586
587 DWORD byte_count = 0;
588 DWORD type = 0;
589
590 // first get the size of the string buffer
591 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL,
592 &type, NULL, &byte_count);
593 HRESULT hr = HRESULT_FROM_WIN32(res);
594
595 if (hr == S_OK) {
596 if (byte_count != 0) {
597 // Allocate some memory and make the call again
598 value->resize(byte_count / sizeof(wchar_t) + 1);
599 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
600 &value->at(0), &byte_count);
601 hr = HRESULT_FROM_WIN32(res);
602 value->resize(wcslen(value->data()));
603 } else {
604 value->clear();
605 }
606
607 ASSERT((hr != S_OK) || (type == REG_SZ) ||
608 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
609 }
610
611 return hr;
612}
613
614// convert REG_MULTI_SZ bytes to string array
Peter Boström0c4e06b2015-10-07 12:23:21 +0200615HRESULT RegKey::MultiSZBytesToStringArray(const uint8_t* buffer,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000616 DWORD byte_count,
617 std::vector<std::wstring>* value) {
618 ASSERT(buffer != NULL);
619 ASSERT(value != NULL);
620
621 const wchar_t* data = reinterpret_cast<const wchar_t*>(buffer);
622 DWORD data_len = byte_count / sizeof(wchar_t);
623 value->clear();
624 if (data_len > 1) {
625 // must be terminated by two null characters
626 if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {
627 return E_INVALIDARG;
628 }
629
630 // put null-terminated strings into arrays
631 while (*data) {
632 std::wstring str(data);
633 value->push_back(str);
634 data += str.length() + 1;
635 }
636 }
637 return S_OK;
638}
639
640// get a std::vector<std::wstring> value from REG_MULTI_SZ type
641HRESULT RegKey::GetValue(const wchar_t* value_name,
642 std::vector<std::wstring>* value) const {
643 ASSERT(value != NULL);
644
645 DWORD byte_count = 0;
646 DWORD type = 0;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200647 uint8_t* buffer = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000648
649 // first get the size of the buffer
650 HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count);
651 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ));
652
653 if (SUCCEEDED(hr)) {
654 hr = MultiSZBytesToStringArray(buffer, byte_count, value);
655 }
656
657 return hr;
658}
659
660// Binary data Get
661HRESULT RegKey::GetValue(const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200662 uint8_t** value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000663 DWORD* byte_count) const {
664 ASSERT(byte_count != NULL);
665 ASSERT(value != NULL);
666
667 DWORD type = 0;
668 HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);
669 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));
670 return hr;
671}
672
673// Raw data get
674HRESULT RegKey::GetValue(const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200675 uint8_t** value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000676 DWORD* byte_count,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200677 DWORD* type) const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000678 ASSERT(type != NULL);
679 ASSERT(byte_count != NULL);
680 ASSERT(value != NULL);
681
682 return GetValueHelper(value_name, type, value, byte_count);
683}
684
685// Int32 set
686HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD value) const {
687 ASSERT(h_key_ != NULL);
688
Peter Boström0c4e06b2015-10-07 12:23:21 +0200689 LONG res =
690 ::RegSetValueEx(h_key_, value_name, NULL, REG_DWORD,
691 reinterpret_cast<const uint8_t*>(&value), sizeof(DWORD));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000692 return HRESULT_FROM_WIN32(res);
693}
694
695// Int64 set
696HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD64 value) const {
697 ASSERT(h_key_ != NULL);
698
699 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_QWORD,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200700 reinterpret_cast<const uint8_t*>(&value),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000701 sizeof(DWORD64));
702 return HRESULT_FROM_WIN32(res);
703}
704
705// String set
706HRESULT RegKey::SetValue(const wchar_t* value_name,
707 const wchar_t* value) const {
708 ASSERT(value != NULL);
709 ASSERT(h_key_ != NULL);
710
711 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_SZ,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200712 reinterpret_cast<const uint8_t*>(value),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000713 (lstrlen(value) + 1) * sizeof(wchar_t));
714 return HRESULT_FROM_WIN32(res);
715}
716
717// Binary data set
718HRESULT RegKey::SetValue(const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200719 const uint8_t* value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000720 DWORD byte_count) const {
721 ASSERT(h_key_ != NULL);
722
723 // special case - if 'value' is NULL make sure byte_count is zero
724 if (value == NULL) {
725 byte_count = 0;
726 }
727
728 LONG res = ::RegSetValueEx(h_key_, value_name, NULL,
729 REG_BINARY, value, byte_count);
730 return HRESULT_FROM_WIN32(res);
731}
732
733// Raw data set
734HRESULT RegKey::SetValue(const wchar_t* value_name,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200735 const uint8_t* value,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000736 DWORD byte_count,
737 DWORD type) const {
738 ASSERT(value != NULL);
739 ASSERT(h_key_ != NULL);
740
741 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);
742 return HRESULT_FROM_WIN32(res);
743}
744
745bool RegKey::HasKey(const wchar_t* full_key_name) {
746 ASSERT(full_key_name != NULL);
747
748 // get the root HKEY
749 std::wstring key_name(full_key_name);
750 HKEY h_key = GetRootKeyInfo(&key_name);
751
752 if (h_key != NULL) {
753 RegKey key;
754 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
755 key.Close();
756 return S_OK == hr;
757 }
758 return false;
759}
760
761// static version of HasValue
762bool RegKey::HasValue(const wchar_t* full_key_name, const wchar_t* value_name) {
763 ASSERT(full_key_name != NULL);
764
765 bool has_value = false;
766 // get the root HKEY
767 std::wstring key_name(full_key_name);
768 HKEY h_key = GetRootKeyInfo(&key_name);
769
770 if (h_key != NULL) {
771 RegKey key;
772 if (key.Open(h_key, key_name.c_str(), KEY_READ) == S_OK) {
773 has_value = key.HasValue(value_name);
774 key.Close();
775 }
776 }
777 return has_value;
778}
779
780HRESULT RegKey::GetValueType(const wchar_t* full_key_name,
781 const wchar_t* value_name,
782 DWORD* value_type) {
783 ASSERT(full_key_name != NULL);
784 ASSERT(value_type != NULL);
785
786 *value_type = REG_NONE;
787
788 std::wstring key_name(full_key_name);
789 HKEY h_key = GetRootKeyInfo(&key_name);
790
791 RegKey key;
792 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
793 if (SUCCEEDED(hr)) {
794 LONG res = ::SHQueryValueEx(key.h_key_, value_name, NULL, value_type,
795 NULL, NULL);
796 if (res != ERROR_SUCCESS) {
797 hr = HRESULT_FROM_WIN32(res);
798 }
799 }
800
801 return hr;
802}
803
804HRESULT RegKey::DeleteKey(const wchar_t* full_key_name) {
805 ASSERT(full_key_name != NULL);
806
807 return DeleteKey(full_key_name, true);
808}
809
810HRESULT RegKey::DeleteKey(const wchar_t* full_key_name, bool recursively) {
811 ASSERT(full_key_name != NULL);
812
813 // need to open the parent key first
814 // get the root HKEY
815 std::wstring key_name(full_key_name);
816 HKEY h_key = GetRootKeyInfo(&key_name);
817
818 // get the parent key
819 std::wstring parent_key(GetParentKeyInfo(&key_name));
820
821 RegKey key;
822 HRESULT hr = key.Open(h_key, parent_key.c_str());
823
824 if (hr == S_OK) {
825 hr = recursively ? key.RecurseDeleteSubKey(key_name.c_str())
826 : key.DeleteSubKey(key_name.c_str());
827 } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
828 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
829 hr = S_FALSE;
830 }
831
832 key.Close();
833 return hr;
834}
835
836HRESULT RegKey::DeleteValue(const wchar_t* full_key_name,
837 const wchar_t* value_name) {
838 ASSERT(full_key_name != NULL);
839
840 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
841 // get the root HKEY
842 std::wstring key_name(full_key_name);
843 HKEY h_key = GetRootKeyInfo(&key_name);
844
845 if (h_key != NULL) {
846 RegKey key;
847 hr = key.Open(h_key, key_name.c_str());
848 if (hr == S_OK) {
849 hr = key.DeleteValue(value_name);
850 key.Close();
851 }
852 }
853 return hr;
854}
855
856HRESULT RegKey::RecurseDeleteSubKey(const wchar_t* key_name) {
857 ASSERT(key_name != NULL);
858
859 RegKey key;
860 HRESULT hr = key.Open(h_key_, key_name);
861
862 if (hr == S_OK) {
863 // enumerate all subkeys of this key and recursivelly delete them
864 FILETIME time = {0};
865 wchar_t key_name_buf[kMaxKeyNameChars] = {0};
866 DWORD key_name_buf_size = kMaxKeyNameChars;
867 while (hr == S_OK &&
868 ::RegEnumKeyEx(key.h_key_, 0, key_name_buf, &key_name_buf_size,
869 NULL, NULL, NULL, &time) == ERROR_SUCCESS) {
870 hr = key.RecurseDeleteSubKey(key_name_buf);
871
872 // restore the buffer size
873 key_name_buf_size = kMaxKeyNameChars;
874 }
875 // close the top key
876 key.Close();
877 }
878
879 if (hr == S_OK) {
880 // the key has no more children keys
881 // delete the key and all of its values
882 hr = DeleteSubKey(key_name);
883 }
884
885 return hr;
886}
887
888HKEY RegKey::GetRootKeyInfo(std::wstring* full_key_name) {
889 ASSERT(full_key_name != NULL);
890
891 HKEY h_key = NULL;
892 // get the root HKEY
893 size_t index = full_key_name->find(L'\\');
894 std::wstring root_key;
895
896 if (index == -1) {
897 root_key = *full_key_name;
898 *full_key_name = L"";
899 } else {
900 root_key = full_key_name->substr(0, index);
901 *full_key_name = full_key_name->substr(index + 1,
902 full_key_name->length() - index - 1);
903 }
904
905 for (std::wstring::iterator iter = root_key.begin();
906 iter != root_key.end(); ++iter) {
907 *iter = toupper(*iter);
908 }
909
910 if (!root_key.compare(L"HKLM") ||
911 !root_key.compare(L"HKEY_LOCAL_MACHINE")) {
912 h_key = HKEY_LOCAL_MACHINE;
913 } else if (!root_key.compare(L"HKCU") ||
914 !root_key.compare(L"HKEY_CURRENT_USER")) {
915 h_key = HKEY_CURRENT_USER;
916 } else if (!root_key.compare(L"HKU") ||
917 !root_key.compare(L"HKEY_USERS")) {
918 h_key = HKEY_USERS;
919 } else if (!root_key.compare(L"HKCR") ||
920 !root_key.compare(L"HKEY_CLASSES_ROOT")) {
921 h_key = HKEY_CLASSES_ROOT;
922 }
923
924 return h_key;
925}
926
927
928// Returns true if this key name is 'safe' for deletion
929// (doesn't specify a key root)
930bool RegKey::SafeKeyNameForDeletion(const wchar_t* key_name) {
931 ASSERT(key_name != NULL);
932 std::wstring key(key_name);
933
934 HKEY root_key = GetRootKeyInfo(&key);
935
936 if (!root_key) {
937 key = key_name;
938 }
939 if (key.empty()) {
940 return false;
941 }
942 bool found_subkey = false, backslash_found = false;
943 for (size_t i = 0 ; i < key.length() ; ++i) {
944 if (key[i] == L'\\') {
945 backslash_found = true;
946 } else if (backslash_found) {
947 found_subkey = true;
948 break;
949 }
950 }
951 return (root_key == HKEY_USERS) ? found_subkey : true;
952}
953
954std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) {
955 ASSERT(key_name != NULL);
956
957 // get the parent key
958 size_t index = key_name->rfind(L'\\');
959 std::wstring parent_key;
960 if (index == -1) {
961 parent_key = L"";
962 } else {
963 parent_key = key_name->substr(0, index);
964 *key_name = key_name->substr(index + 1, key_name->length() - index - 1);
965 }
966
967 return parent_key;
968}
969
970// get the number of values for this key
Peter Boström0c4e06b2015-10-07 12:23:21 +0200971uint32_t RegKey::GetValueCount() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000972 DWORD num_values = 0;
973
974 if (ERROR_SUCCESS != ::RegQueryInfoKey(
975 h_key_, // key handle
976 NULL, // buffer for class name
977 NULL, // size of class string
978 NULL, // reserved
979 NULL, // number of subkeys
980 NULL, // longest subkey size
981 NULL, // longest class string
982 &num_values, // number of values for this key
983 NULL, // longest value name
984 NULL, // longest value data
985 NULL, // security descriptor
986 NULL)) { // last write time
987 ASSERT(false);
988 }
989 return num_values;
990}
991
992// Enumerators for the value_names for this key
993
994// Called to get the value name for the given value name index
995// Use GetValueCount() to get the total value_name count for this key
996// Returns failure if no key at the specified index
997HRESULT RegKey::GetValueNameAt(int index, std::wstring* value_name,
998 DWORD* type) {
999 ASSERT(value_name != NULL);
1000
1001 LONG res = ERROR_SUCCESS;
1002 wchar_t value_name_buf[kMaxValueNameChars] = {0};
1003 DWORD value_name_buf_size = kMaxValueNameChars;
1004 res = ::RegEnumValue(h_key_, index, value_name_buf, &value_name_buf_size,
1005 NULL, type, NULL, NULL);
1006
1007 if (res == ERROR_SUCCESS) {
1008 value_name->assign(value_name_buf);
1009 }
1010
1011 return HRESULT_FROM_WIN32(res);
1012}
1013
Peter Boström0c4e06b2015-10-07 12:23:21 +02001014uint32_t RegKey::GetSubkeyCount() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001015 // number of values for key
1016 DWORD num_subkeys = 0;
1017
1018 if (ERROR_SUCCESS != ::RegQueryInfoKey(
1019 h_key_, // key handle
1020 NULL, // buffer for class name
1021 NULL, // size of class string
1022 NULL, // reserved
1023 &num_subkeys, // number of subkeys
1024 NULL, // longest subkey size
1025 NULL, // longest class string
1026 NULL, // number of values for this key
1027 NULL, // longest value name
1028 NULL, // longest value data
1029 NULL, // security descriptor
1030 NULL)) { // last write time
1031 ASSERT(false);
1032 }
1033 return num_subkeys;
1034}
1035
1036HRESULT RegKey::GetSubkeyNameAt(int index, std::wstring* key_name) {
1037 ASSERT(key_name != NULL);
1038
1039 LONG res = ERROR_SUCCESS;
1040 wchar_t key_name_buf[kMaxKeyNameChars] = {0};
1041 DWORD key_name_buf_size = kMaxKeyNameChars;
1042
1043 res = ::RegEnumKeyEx(h_key_, index, key_name_buf, &key_name_buf_size,
1044 NULL, NULL, NULL, NULL);
1045
1046 if (res == ERROR_SUCCESS) {
1047 key_name->assign(key_name_buf);
1048 }
1049
1050 return HRESULT_FROM_WIN32(res);
1051}
1052
1053// Is the key empty: having no sub-keys and values
1054bool RegKey::IsKeyEmpty(const wchar_t* full_key_name) {
1055 ASSERT(full_key_name != NULL);
1056
1057 bool is_empty = true;
1058
1059 // Get the root HKEY
1060 std::wstring key_name(full_key_name);
1061 HKEY h_key = GetRootKeyInfo(&key_name);
1062
1063 // Open the key to check
1064 if (h_key != NULL) {
1065 RegKey key;
1066 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
1067 if (SUCCEEDED(hr)) {
1068 is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0;
1069 key.Close();
1070 }
1071 }
1072
1073 return is_empty;
1074}
1075
1076bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable) {
1077 ASSERT(privilege != NULL);
1078
1079 bool ret = false;
1080 HANDLE token;
1081 if (::OpenProcessToken(::GetCurrentProcess(),
1082 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
1083 LUID luid;
1084 memset(&luid, 0, sizeof(luid));
1085 if (::LookupPrivilegeValue(NULL, privilege, &luid)) {
1086 TOKEN_PRIVILEGES privs;
1087 privs.PrivilegeCount = 1;
1088 privs.Privileges[0].Luid = luid;
1089 privs.Privileges[0].Attributes = to_enable ? SE_PRIVILEGE_ENABLED : 0;
1090 if (::AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, 0)) {
1091 ret = true;
1092 } else {
1093 LOG_GLE(LS_ERROR) << "AdjustTokenPrivileges failed";
1094 }
1095 } else {
1096 LOG_GLE(LS_ERROR) << "LookupPrivilegeValue failed";
1097 }
1098 CloseHandle(token);
1099 } else {
1100 LOG_GLE(LS_ERROR) << "OpenProcessToken(GetCurrentProcess) failed";
1101 }
1102
1103 return ret;
1104}
1105
1106} // namespace rtc